Five times in this project a green test meant nothing was checked. The
continuity smoke stayed green after the entire mechanism it guards was cut out.
The golden scene created to protect doorway light was empty — 1,177 warm pixels
against 107,119, all of them icons. The shadow smoke passed while no shadow was
drawn. Each time the test had been written alongside the code, went green at
once, and nobody ever asked whether it could go red.
The gate makes that question routine. Each mutant is a few lines of patch that
reproduce a known breakage, plus the name of the test that must fail on it. A
worktree is patched, the bundle rebuilt, the guard run — and a guard that stays
green fails the gate. Six mutants cover the holes documented in #85; the anchors
are exact strings from today's source, so the registry cannot silently drift —
a unit test that runs with the ordinary suite refuses a stale anchor.
The full run rebuilds the bundle per mutant, so it lives in its own workflow,
before a stable release and on a weekly schedule, not in Validate. The rules for
new tests are written at the top of docs/TESTING.md, and the sixth of them is
the cheapest: an assertion that reads back the property the code just set is
not written at all.
Issue: #85
User-Visible: no
The owner's report: the process works but every stage takes a long time even on
simple bugs. Two causes, and neither was the one that first comes to mind.
The reviewer ran everything regardless. On #89 it installed Chromium, ran all 127
smoke files and a full golden capture — right for a task rated 10/10 for
complexity, absurd for a bug about a room divider. Full suites are the pre-beta
gate; the review now runs typecheck, unit and build always, and smokes, golden,
pytest or performance only where the diff and the AC call for them. The price of
narrowing it is honesty: the reviewer must list which gates it ran, which it did
not, and why, so a skipped gate is a visible decision rather than a silent one.
The reviewer also built its own environment out of model turns, with no npm cache
and no browser cache, paid for from the same forty-five minutes. The workflow now
installs dependencies and Chromium as ordinary cached steps, after switching to
the task branch so the lockfile is the branch's own.
Second, ceremony did not scale down. The light track makes a spec cheap; the new
trivial track does without one — S2-analysis straight to S5-ready, no spec review,
AC in the issue body. It is deliberately hard to qualify for: a bug on one surface,
no new UX contract, no migration, no i18n, no perf or touch effect, three checkable
AC at most, and expected behaviour already on record. Nothing left to decide is the
criterion that holds the whole thing up, and it cannot be met by feeling sure.
Code review is never skipped on either track. It is what stands in for testing
here, so it is the one stage speed may not buy.
Issue: #127
Issue: #128
User-Visible: no
Issues labelled before the pipeline existed keep their spec straight in dev and
have no issue/NN branch. The publish step quietly exited zero for them, so the
verdict would arrive as a comment and the analysis behind it would be thrown
away — the fifth instance today of a step reporting success by doing nothing.
The document now goes wherever the spec itself lives: the task branch when there
is one, dev otherwise. Publishing also survives dev moving on while the review
ran, which takes up to forty-five minutes, by rebasing once before it gives up.
Four issues are waiting on this — #12, #30, #44 and #52 — each with a spec in dev,
a status label applied during the bulk pass in August and a review that never ran
because nothing was there to raise the event.
Issue: #114
User-Visible: no
The two copies of this file must match byte for byte; a comment line had drifted
by one character. main is the copy the issues event actually reads, so it is the
reference. Trivial in itself, and worth closing anyway: the file's own header
warns that a divergence between these two branches is one of the ways this
pipeline fails quietly.
Issue: #114
User-Visible: no
The guard refused to review any issue the owner had not filed himself. The rule
was meant to keep malformed outside reports out of the pipeline, but it checked at
every step instead of at the entrance, and it duplicated a guarantee the platform
already gives: only someone with write access can apply a label. Applying the
first status label is the owner's explicit decision, and it is the only place the
question belongs.
So the author check is gone. While an issue carries no status label it sits
outside the process and the invariants do not apply; once labelled, the task is in
flight and who filed it stops mattering.
The old rule also cost real work. On #123 an outside bug report had been analysed
and specified before the guard turned it away in nine seconds, and the remedy on
offer was to refile the same thing as the owner's own issue.
Issue: #114
User-Visible: no
A review label promises work. When the guard declined it wrote the reason to the
run log and nothing else, so the issue sat in a status nobody was acting on and
nobody could tell. #123 showed it: an outside reporter's issue was walked up to
S4-spec-review, the guard refused in nine seconds because only the owner's issues
enter the process, and the issue itself said not a word.
Refusals that a human can act on now become a comment: wrong author, blocked,
review-4. Only when a stage was actually recognised, so an unrelated label change
stays silent.
This is the same defect as the merge conflict that left the label untouched, seen
from the other side. The pattern is worth naming: doing nothing quietly is the
most expensive thing a pipeline can do.
Issue: #114
User-Visible: no
A green code review whose merge conflicted used to leave the label where it was.
That is a dead end: the author waits for the label to change, so it polled thirty
times and reported the limit as exhausted — on a task the reviewer had already
passed. The verdict existed and nobody could act on it.
The merge step no longer fails the job. It reports whether it merged, and a green
review that did not merge sends the task back to S6-in-progress, because the work
did return to the author — a rebase rather than a code fix, and the comment says
so and says the verdict still stands.
The invariant is now stronger and worth stating plainly: after a review run the
label always changes. A pipeline whose state can stall silently is worse than one
that reports the wrong state loudly.
Issue: #114
User-Visible: no
The step that comments on the issue when a review run dies carried a literal
backslash instead of a line continuation, so gh received four arguments and
--repo ran as a command of its own. The handler for failures would itself have
failed, silently, and only when something had already gone wrong.
bash -n does not catch this: the syntax is valid, the meaning is not. Checking
run blocks now also means looking for a doubled backslash at end of line.
Issue: #114
User-Visible: no
The guard counted every verdict comment on the issue, so a spec-review verdict
consumed a cycle from the code-review budget. On #89 the first code review came
out as r2/4. With two spec cycles the second code review would have hit review-4
after a single fix — the limit would have fired on a task nobody had reviewed
twice.
The stage is now resolved first and only its own verdicts are counted, recognised
by the review document named in the comment. If the document is missing the
verdict is not counted: undercounting grants an extra cycle, overcounting would
stop the work early, and of the two mistakes the recoverable one wins.
Issue: #114
User-Visible: no
PROCESS.md 10.2 item 10 asks for this to happen because a beta shipped, not
because someone remembered. The manual cleanup was skipped twice and both times
it broke the invariant that a closed issue carries no status label — the one
thing `verify` leans on. A manual step that falls due right after a successful
release is the worst kind: the work already looks finished, which is precisely
why it gets forgotten.
The job comments the tag, removes the label, then closes. That order is
deliberate: dying between the two steps leaves an open issue without a status,
which is visible and fixable in the flow, where the reverse order would recreate
the breakage this exists to prevent. It ends by asserting that no closed issue
still carries S8-merged — aimed at the defect that actually recurs rather than at
the invariant in general.
The stock token is used on purpose. Events caused by GITHUB_TOKEN do not start
workflows, so stripping the label cannot wake the review pipeline; a PAT here
would turn bookkeeping into a cascade.
Issue: #120
User-Visible: no
PROCESS.md 10.2 describes scripts/process-gate.mjs; the script never existed.
Commits go straight to dev without PRs and GitHub blocks nothing on its side, so
until now the only thing standing between the process and rule #1 was the good
faith of whoever was committing. Hooks catch a violation on the author's machine
but --no-verify walks past them; this job is the catch-up pass that cannot be
skipped locally.
Checks 1-7 offline, 8 through gh, plus the escalation of check 3: a class A
commit with neither a spec file nor the `small` label is a failure, not a
warning. Check 8 is fail closed — an unreachable or closed issue is a refusal,
never a silent pass.
Two things surfaced while wiring it up and are recorded in the script header.
S8-merged had to join the allowed statuses: the pipeline merges into dev before
it moves the label, so Validate reads the issue already advanced and a strict set
would redden every accepted task. And the status question now applies only to
class A/B commits — asking it of a review document would fail every time, since
that document lands while the issue sits in S4-spec-review or S7-code-review.
Issue: #105
User-Visible: no
Keeps dev identical to main so the broken revision does not come back at the
next promotion. The workflow only fires from the default branch, but a stale
copy here would overwrite the working one.
Issue: #114
User-Visible: no
Pushing the hook through the GitHub contents API dropped its mode to 100644.
assertHookMode caught it on the next commit, which is the gate working as
intended — a non-executable commit-msg would simply never run.
Also brings dev in line with the turn-limit fix already on main.
Issue: #116
User-Visible: no
The first live run failed with "Could not fetch an OIDC token": the action
needs id-token: write to authenticate the GitHub App.
The reviewer also checked out dev, where the material under review does not
exist yet — specs and code are committed to issue/<NN>-slug. The job now
switches to that branch when it is pushed, and warns loudly when it is not.
Issue: #114
User-Visible: no
Adds .github/workflows/process.yml. A status label change is the trigger:
S4-spec-review runs the spec review, S7-code-review runs the code review,
and the verdict decides the next label. Only a green verdict advances;
yellow and red return the task to its author. Cycle limits (4, or 2 on the
light track) are counted from the verdicts already posted on the issue.
Labels are moved with HP_PROCESS_TOKEN, not GITHUB_TOKEN, so the change
emits an event and the chain continues.
Issue: #114
User-Visible: no
HACS will install from the named asset instead of the auto zipball, so
GitHub's public download counter becomes a per-version install metric.
The workflow also has a manual dispatch to backfill an existing release.
- badges + header line in README.md / README.ru.md
- 'Getting help & sharing your plan' section in both READMEs, asking for
the version number when reporting (console banner / integration page)
- .github/ISSUE_TEMPLATE/config.yml contact links (chat + discussions)
- CONTRIBUTING 'Where to ask'; STATUS (community row) and SCOPE (field
feedback source)
T1: demo/serve.mjs exports check/checkAll/finish — all 48 smokes now
assert named facts and exit non-zero on a mismatch or an uncaught
in-card exception (verified by breaking the kiosk guard on purpose).
Informational values were frozen from a v1.43.1 run and cross-read
against the source; timings assert budgets, not exact numbers.
T2: new CI job 'smoke' gated on 'frontend', builds a FRESH bundle
before running (the committed demo/srv/assets copy is a snapshot) and
uploads per-file logs on failure.
T3: [auto] now means 'a named failing check exists' and each line names
it (43 lines); 72 aspirational markers honestly downgraded to [manual].
Fixed the 'ZERO edit buttons' contradiction (wrong since v1.30.1) and
the opening-click line (true again since v1.43.1).
Three smokes carried pre-v1.39.0/v1.25 expectations and were testing
old behaviour: tap defaults for lights, card-wide tap action, label drag
requiring plan mode.
DEVELOPMENT.md documents the harness contract.