Version. v0.1
Date. 2026-08-04
Author. Claude.ai (drafting session). Approving: Marvin Percival.
Charter. standing-notes/dunin7-standing-authorization-charter-v0_1. No session executes a change request it drafted (§1).
Target. /Users/dunin7/loomworks-engine at main 7bdbf8b; /Users/dunin7/loomworks at main 7a9adc9. Two repositories, separate branches, separate merges and tags.
Baselines. Both repositories pass every candidate gate command, deterministically, established across two runs each at Step 0. The criterion is that they still do, plus the gates themselves.
Build-list item. B-49.
CR number. CR-2026-167. Highest confirmed is CR-2026-166. [EXECUTING SESSION: verify; advance if taken.]
Grounding. inspection-briefs/loomworks-b49-step-0-findings-v0_1 — every fact below was read or run there.
Status. Pre-execution.
Nothing enforces anything. No pull request is ever opened in either repository; every merge is local --no-ff pushed straight to main. The surface has no workflow files and no branch protection at all. The engine has one workflow, and it has never passed — not once since June, across every run in its history, including against the commit this change request targets.
Both repositories pass their own checks right now. That is the window: a gate installed over a clean state simply holds. Installed later, it is an argument about what to grandfather.
A permanently-red pipeline is not a weaker version of no pipeline. It is worse, because it teaches everyone that red means nothing — and a new gate installed beside it inherits that. The engine's existing check has been red for two months and its failure has never been acted on.
It is failing on real drift: the API documentation is dozens of commits behind the schema it describes. So the check is working and the docs are wrong, which is the opposite of the vacuous-pass hazard this change request was scoped expecting.
Two resolutions, and Step 0 chooses between them on evidence:
[EXECUTING SESSION: establish whether anything reads the generated OpenAPI documentation — the record, the marketing site, a client, a test, an external consumer. Report before choosing. If it is consumed, regenerating is not optional and the drift is its own finding.]
Nothing else in this change request is installed until this is resolved.
main, and the reason is honest rather than ideal.Gating a pull request is the better design and this project opens none. Every merge is local and pushed directly. A pull-request gate would be installed, look correct, and never fire once — which is the vacuous-green hazard exactly, built deliberately.
So: on push to main. It reports after the fact rather than preventing, and that is what this project's actual process admits.
> What it is worth, stated plainly rather than oversold. It does not stop a bad merge. It does three things the current arrangement does not: it notices drift arriving by any route, it makes the state readable without anyone running anything, and it produces a record of when a break started — which every investigation this month has had to reconstruct by hand.
Set aside, recorded: adopting pull requests. That is a change to how this project works, not a gate, and it belongs to the Operator rather than to a change request about automation.
A gate whose failure mode nobody has seen is a claim, not a check — and this repository's one existing check demonstrates the inverse failure just as clearly.
For each gate installed, demonstrate a failure locally: break the thing it guards, confirm the command exits non-zero, restore. Record what was broken and what the output was. A gate that has only ever been observed passing has not been observed.
Several documents in this project have carried figures that drifted, and a gate is the worst place for one. A gate asserting a test count fails the next time a test is added; a gate asserting an error count passes when a new error replaces a fixed one.
Gates assert conditions: the command exits zero. [EXECUTING SESSION: confirm no installed gate encodes a count, a duration, or a version that will move.]
ruff and mypy are not gated — that is B-48's decision and not this one. A green pipeline that runs tests and not type checks says something by omission, and a reader will take it as meaning more than it does.
The workflow file carries a comment naming what it runs and what it deliberately does not, with B-48 named as the open decision. This is the governing rule applied to a pipeline: a green report says only what was actually checked.
Setting LOOMWORKS_ENV=test locally trips a posture guard and produces collection errors that look like real failures. A future gate configured with that variable would report a break that does not exist, and someone would spend a day on it.
Recorded in the engine's README beside the stand-up sequence, and in the workflow's own comment.
They cannot run in CI as currently configured. Not gated, and named as not gated in D-5's coverage comment — so the gap is visible rather than silently absent.
3.1 Engine — resolve the existing workflow, per D-1: regenerate or remove, on Step 0's evidence.
3.2 Engine — a workflow gating the test suite on push to main. It needs a database; the README's stand-up sequence is the reference for what a fresh runner must provide.
3.3 Surface — a workflow gating lint, tests and build on push to main. The surface has no workflow file at all today, so this creates the first one.
3.4 Both — the coverage comment at D-5, and the environment note at D-6.
ruff and mypy. B-48's decision.Per-step commits. Two repositories, two branches. Never one commit spanning both. Check the current branch before the first commit in each.
Step 0 — pre-flight, baselines, and one determination. Verify both HEADs and trees, the CR number. Record every candidate gate command's current result and duration. Re-confirm the findings' anchors.
Then settle: is the generated API documentation consumed by anything? Per D-1. Report before proceeding.
Step 1 — engine, D-1's resolution. Whichever branch Step 0 selects. Verify the workflow's state changes from red — either to green, or to absent.
Step 2 — engine, the test-suite gate. §3.2.
Step 3 — surface, the lint/test/build gate. §3.3.
Step 4 — the failure demonstrations, per D-3. Every gate, locally, one at a time. Record what was broken and the output.
Step 5 — the coverage comment and the environment note, per D-5 and D-6.
CHECKPOINT A — report, then proceed. Baselines; Step 0's determination; the failure demonstration for every installed gate; and confirmation that no gate encodes a moving figure. No Operator confirmation. Halt and queue on: any gate that cannot be demonstrated failing; the documentation determination coming back ambiguous; any new failure; any charter §6 anomaly.
Step 6 — implementation notes in each repository.
CHECKPOINT B — merge and tag, separately per repository. --no-ff in each; tag the engine engine-ci-gate-v0_1 and the surface surface-ci-gate-v0_1. Push both. Authorized under R-2 including the pushes.
> And then watch them run. These gates fire on push, so Checkpoint B is the first time they execute for real. Report the outcome of the first run in each repository — a gate that passes locally and fails on a fresh runner is the ordinary case, not a surprise, and finding that out here is the point of installing them now rather than later. [EXECUTING SESSION: if a first run fails on an environment difference, that is a result. Fix it and report both; do not disable the gate to make the merge look clean.]
Deployment is never autonomous (F-1) — and nothing here reaches the serving perimeter.
main, and its first real run's outcome is reported.main, and their first real run's outcome is reported.LOOMWORKS_ENV=test trap is documented in the engine's README and the workflow comment.
CR-2026-167 — B-49, gating what is clean. Execution session.
CR: loomworks-record/change-requests/cr-2026-167-ci-gates-v0_1.md
Confirm it exists, and that it is the highest version present — numeric sort.
Grounding, read before the CR:
inspection-briefs/loomworks-b49-step-0-findings-v0_1.md
Charter dunin7-standing-authorization-charter-v0_1 governs.
Read the CR in full. It is the authority on what changes, where and why; this
block repeats none of it. Where this block and the CR appear to differ, the CR
is right and you halt rather than choosing.
Section 2 — the construction decisions and their reasoning
Section 3 — what changes
Section 4 — what is out of scope
Section 5 — the step sequence and both checkpoints
Section 6 — the acceptance gate
TWO REPOSITORIES — the CR's header names both targets. Separate branches,
separate commit series, separate merges and tags.
This CR installs automation that runs on push. Checkpoint B is therefore the
first time these gates execute for real, and their outcome is part of the
report. A gate that passes locally and fails on a fresh runner is an ordinary
result — fix it and report both. Do not disable a gate to make a merge look
clean.
Standing fences, true regardless of this CR:
playground_dev and playground_test are live databases and are not touched.
If the engine's suite needs a database, use a throwaway, dropped after.
Commit to a branch; check the current branch before the first commit in each.
Deployment is never yours.
Append the outcome to current-status/dunin7-status-brief at close.
DUNIN7 — Done In Seven LLC — Miami, Florida CR-2026-167 — B-49: gating what is clean — v0.1 — 2026-08-04 Both repositories pass today. This is what makes them keep passing, and says plainly what it does not check.