Feat/criterion vocabulary rollup - #143
Merged
Merged
Conversation
…air plan
Two audits close, both by handing their remainder to tasks that already existed —
which is what `tracked` is for, and the first real use of it outside the branch
that introduced it:
* 2026-08-22-multi-workspace-atlas — M2/M4 were atlas FEATURES (branch badges,
live filter), not defects in what shipped. Both already had tasks on epic 29.
12/12 settled, closed.
* 2026-08-24-finding-note-and-vocabulary-selfreview — M3 folded into the
acceptance-criterion vocabulary task as criterion 10. It is a decision about a
shared word, and deciding it apart from that task's other open questions would
be deciding it twice. 10/10 settled, closed.
audit-lint-fix-for-legacy-finding-status-debt is rewritten rather than edited. Its
scope had gone from stale to actively harmful: it specified mapping `tracked` →
`superseded`, which would now DESTROY a handoff rather than repair anything, and it
listed `landed` as legal. Its emoji-stripping half is largely obsolete since the
parser became decoration-tolerant. The replacement leads with measuring what debt
actually remains — plausibly none — and forbids any repair that silently changes a
status's meaning, with its own former rule as the cautionary example.
audit-finding-write-surface completes: 3 criteria met, 2 tracked to the
candidate-list convention task. H2 of 2026-08-17-finding-status-surface is tracked
to the lint-fix task above.
Criteria wrap — the corpus wraps them — but the scanner only ever captured the
marker line, so every wrapped criterion was truncated at the fold in `task ac
--list`, `task show`, and the JSON:
"Criterion states reuse the finding glyph/colour vocabulary rather than introducing a"
with "parallel one." silently dropped. Worse, the state writer appended its suffix
to the end of that same first line, splitting the sentence and stranding the tail
beneath the reason:
- [ ] …rather than introducing a · **deferred:** no glyph vocabulary rendered yet
parallel one.
The scanner now tracks a criterion's last line, joining continuations — indented,
non-blank, not themselves list items — and stopping where a markdown reader stops:
a blank line, a new list item, a heading, or a fence. Text is the whole criterion.
The writer strips an existing suffix from wherever it sits and appends the new one
to the criterion's LAST line.
Two bugs only surfaced by re-setting a state: stripping the suffix trimmed the
continuation's indentation, which made the line stop being a continuation, so the
NEXT write left its suffix stranded and `met` no longer cleared it. Indentation is
now preserved through the strip.
TestSetAcceptanceCriterion_MultiLine asserted the truncated text, so it had been
holding the bug in place rather than catching it.
Repairs the one file in the corpus this damaged — this task's own criteria 8 and 9,
found by starting the task and reading them.
Once a criterion can say `deferred` or `wontfix`, that state is decision-shaped and
belongs where decisions are read — not several screens into the body prose. The
task detail header now carries a roll-up:
acceptance ███████▒▒▒▒░ 6/10 ✔ 6 · ○ 1 · ◌ 3
Shaped after the audit finding bar on purpose, and drawn by the same renderer: met
is the done band, everything settled-but-not-met is the dropped band, and still-open
criteria are the empty track. Criteria have no in-progress state, so the active band
is always zero. Absent entirely on a task with no criteria, which is most of them.
The glyphs are the FINDING glyphs. theme.CriterionState delegates every shared word
to theme.FindingStatus rather than restating it, so `◌ deferred` is the same mark on
a criterion as on a finding by construction — and TestCriterionStateReusesFindingGlyphs
fails if the two ever diverge. `met` and `not met` borrow the marks of `fixed` and
`open`; `n/a` is the one state findings have no word for, so it takes its own mark,
and the test asserts it collides with none of theirs.
`task ac` gets the same treatment. It had been rendering every state in one warn
yellow — identical for deferred, wontfix, and n/a — which is precisely the second
visual language this criterion rules out.
`task complete` accepted a task with every criterion unticked. It now refuses when a
criterion is unmet AND carries no state, and completes when each one is either met
or explained. --force overrides.
error: task "…" has 7 acceptance criterion/criteria still unmet with no reason
(#1, #2, #3, #4, #5, #6, #7); tick them, give each a state
(`task ac --defer|--wontfix|--tracked|--na`), or pass --force
This is the task counterpart of a rule the tool already had: MoveAudit refuses to
close an audit with open findings. The guard sits in the same place — the store,
before the dry-run return — so a preview fails identically to the real write instead
of passing and then failing.
What makes the gate tolerable is the vocabulary. Before it, "refuse on unmet
criteria" meant "tick every box or never finish", because an unticked box was the
only thing a criterion could say. Now it can say `wontfix`, `deferred`, `tracked`, or
`n/a`, and each is a DECISION — so the gate blocks silence, not disagreement. A task
with three explicitly abandoned criteria completes; one with three nobody looked at
does not.
force is threaded through Store.Move rather than added as a separate Complete path,
so the TUI's lifecycle transition is held to the same rule as the CLI's and surfaces
the refusal as its error flash. Only completion is gated: deferring a task with
unmet criteria is the normal case.
The smoke test now proves the refusal at the exit-code boundary through a real
process, then ticks and completes — it had been silently relying on completion
accepting anything.
Closes M5 of 2026-07-24-ai-agent-cli-ergonomics and criterion 6 of
let-an-acceptance-criterion-say-more-than-done-or-not-done, which is now complete.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.