Skip to content

[#220] feat: breakdown-to-task feedback loop (close tasks + comment) - #468

Merged
rucka merged 8 commits into
mainfrom
feature/US-220-breakdown-task-feedback-loop
Sep 14, 2026
Merged

rucka merged 8 commits into
mainfrom
feature/US-220-breakdown-task-feedback-loop

Conversation

@rucka

@rucka rucka commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

PR Information

PR Title: [#220] feat: breakdown-to-task feedback loop (close tasks + comment)
Story/Epic: #220 · epic #212
Type: Feature
Priority: Should-Have (P1)
Assignee: rucka
Labels: risk:yellow

Summary

What Changed

As /implement advances through a story's inline task breakdown, it ticks the completed checklist
item and posts ONE batched progress comment per run iteration. Manual and supervised runs share one
mechanism because the supervised path reaches it through /loop/implement-batch/implement
rather than reimplementing it.

  • New KB guideline task-progress-feedback.md — scope + one owner, task-ID checklist locator,
    tick-only body patch (four properties: full-body-overwrite transport, diff-checked write, one
    write per checkbox
    , never unticks), batching + comment format (D22), outcome vocabulary and
    where each outcome is produced, failure/conflict handling, what never happens.
  • /implement (v0.6.1 → 0.7.3): /write-issue added as Optional; Step 2.1 owns the
    skipped path (a task that cannot be attempted is queued with its reason, at most once per
    invocation
    , not HALTed); Step 2.8 item 7 ticks and queues on every commit strategy (item 2
    routes commit-per-story through it instead of short-circuiting); Step 3.1 item 7 is catch-up
    only, scoped to tasks completed in this invocation; Step 3.1b flushes exactly one batched
    comment before the checkpoint step and drains the queue; Step 3.1's commit-per-task skip
    routes through 3.1b; the HALT preamble flushes unless 3.1b already did; Progress: row on
    the output block.
  • /write-issue (v0.9.0 → 0.11.0): Composition Interface entry for /implement, plus a new
    $on-failure argument (halt default / report) and a new Step 8b — under report the
    three tracker-side HALTs return not-found / membership-unconfirmed / write-failed to the
    caller instead of raising. The carve-out is written at each HALT site and on the canonical
    ## HALT Conditions rows, because that is what an agent executing the numbered steps reads.
    Argument/configuration HALTs (Steps 1, 3, 6) still fire for every caller.
  • /loop (v0.1.0 → 0.1.1): one Boundaries bullet — never posts its own per-task progress
    comments.
  • Conformance suite task-progress-feedback.test.ts86 assertions over both guideline
    copies, the three skills and the two docs pages.
  • Docs site: developer-journey/execution.mdx "Progress Feedback: Ticks and One Comment"
    (locator / one-checkbox-per-write / conflict rules stated inline, plus the non-blocking transport);
    reference/guidelines-catalog.mdx PM-tools row.
  • ADL 2026-08-28-task-progress-feedback-is-one-mechanism-owned-by-implement.md.

Why This Change

An unattended run was invisible at task granularity — the checklist and the comments moved only at
PR-open/merge, so a story on task 3 of 4 and a story that failed on task 2 looked identical on the
board, and the only witness to the difference was a session that no longer exists. R4.6 / spec G10 /
D22 ask for that signal without a second implementation the manual and supervised paths could
drift apart on.

Story Context

User Story: As /implement advances through a story's inline task breakdown, tick the completed
checklist item and post ONE batched progress comment per run iteration, so an unattended run is
visible at task granularity. Manual and supervised runs must use one mechanism.

Acceptance Criteria coverage:

AC Where it landed Evidence
Tick the completed checklist item task-ID locator + tick-only patch, one write per checkbox (guideline); queued at Step 2.8 on both commit strategies locator / patch-diff / one-write-per-checkbox assertions over both guideline copies; ticks and queues on BOTH commit strategies
One batched comment per run iteration (D22) Step 3.1b — reachable on both strategies, draining, never re-flushed by a later HALT, never re-queued by a no-op re-invocation no Phase-3 skip jumps over the flush (+ its mutation test), never flushes twice in one invocation, does not re-queue a task an earlier invocation completed
Failure and skip are recorded, never ticked outcome vocabulary; skipped produced at task selection (Step 2.1), at most once per invocation; failed at HALT has an explicit call site that queues \skipped`, queues `skipped` at most once per invocation, not once per scan, says where `skipped` is produced`
Manual and supervised use one mechanism /loop never posts its own; supervised inherits via /implement-batch/implement /loop Boundaries bullet + conformance assertion
PM write failure: retry then continue; missing feedback never blocks implementation /write-issue Optional in Composed Skills and the tick composed with $on-failure: report (its Step 8b) so a tracker failure cannot HALT the caller Step 7 / Step 7b beat 4 / Step 8 returns … instead of HALTing, the canonical HALT Conditions list agrees with the steps, keeps the exemption narrow
Failure/conflict handling guideline "Failure and conflict handling" — read-back confirmation, fresh-read retry, exactly one retry, comment-only fallback task-progress-feedback.test.ts

Changes Made

Implementation Details

  • Task-ID checklist locator + tick-only body patchcfa5533f
  • Comment batcher (one per run iteration, D22) + outcome vocabularyc3892c47
  • Wire the feedback loop into /implement (manual + supervised)f1bc8684
  • Conflict/write-failure fallbacks + docs site + ADLb83388f2
  • Review fixes67a74098, 6f86947b, 608b77d2 (folded into the properties above)

Files Changed

  • Modified: the three dataset skills (.skills/capability/write-issue, .skills/loop,
    .skills/process/implement) and their generated .claude/skills/** mirrors;
    .pair/knowledge/.../project-management-tool/README.md (+ dataset source); .pair/llms.txt;
    apps/website/content/docs/developer-journey/execution.mdx;
    apps/website/content/docs/reference/guidelines-catalog.mdx
  • Added: packages/knowledge-hub/dataset/.pair/knowledge/guidelines/collaboration/project-management-tool/task-progress-feedback.md
    (+ its generated .pair/knowledge/** mirror);
    packages/knowledge-hub/src/conformance/task-progress-feedback.test.ts;
    .pair/adoption/decision-log/2026-08-28-task-progress-feedback-is-one-mechanism-owned-by-implement.md

All content is markdown/KB — no runtime code, no schema, no API, no dependency change.

Testing

Test Coverage

  • Unit Tests: task-progress-feedback.test.ts86 assertions; whole
    @pair/knowledge-hub suite 4982 passing (49 files).
  • End-to-End Tests: pnpm --filter @pair/website e2e — 39 Playwright tests passing.
  • Manual Testing: the mechanism was exercised on this very story — all four tasks ticked
    on issue Breakdown-to-task feedback loop (close tasks + comment) #220 and exactly one batched progress comment posted (5453972232, headline
    **Task progress — 4 of 4 tasks this iteration**), with no accretion across the branch's
    several /implement re-invocations.

Test Results

task-progress-feedback.test.ts : ✅ 86/86
@pair/knowledge-hub            : ✅ 4982/4982 (49 files)
pnpm quality-gate              : ✅ exit 0
pnpm smoke-tests (--ci)        : ✅ SUCCESS
website e2e (Playwright)       : ✅ 39 passed

Testing Strategy

  • Happy path: the tick lands, the outcome queues, one comment flushes at Step 3.1b.
  • Edge cases pinned by assertion: locator zero/multi match; a two-checkbox write; an
    already-[x] item; a re-invocation that did no work (must post nothing); commit-per-story
    (auto-selected for every single-task story); a HALT after the flush already posted; a task
    blocked and re-scanned on every later pass.
  • Error handling: a tracker error / unresolvable id / unconfirmed board membership now returns
    an outcome to queue instead of a HALT that propagates into the run.
  • Mutation-proofed: every assertion added this round was verified to redden only its own
    test when its target clause is deleted (11 mutations, one per pin).

Quality Assurance

Code Quality Checklist

  • Code follows established style guides and conventions
  • Error handling implemented for edge cases (conflict / write-failure / HALT-propagation)
  • No debugging code or console logs left behind

Documentation

Documentation Updates

  • Technical Documentation: guideline task-progress-feedback.md; docs-site section in
    execution.mdx (locator / one-checkbox-per-write / conflict rules stated on the page, not
    promised behind a link); guidelines-catalog.mdx updated.

Knowledge Sharing

  • Technical Decisions: ADL 2026-08-28-task-progress-feedback-is-one-mechanism-owned-by-implement.md
    — one mechanism, owned by /implement, batched per invocation; the transport does not HALT for
    the tick ($on-failure: report); a batch lost with its session is not recovered. Rejected:
    a loop-side implementation, a dedicated /report-progress skill, one comment per task, one
    comment at merge, a tick-only $mode on /write-issue, a persisted cross-invocation queue.

Reviewer Guide

Review Focus Areas

  1. $on-failure as the carve-out shape. The tick rides /write-issue write mode, whose
    HALTs propagate into the caller. Comment mode's exemption is keyed on $mode, and a tick mode
    was already rejected (it would make /write-issue an owner of the checklist grammar), so the
    exemption is keyed on a failure-policy argument instead. It is deliberately narrower than
    comment mode's: only the three intermittent tracker-side failures. Is that the right line?
  2. Ticking on commit-per-story happens before the single commit exists (Step 3.1 commits). Is
    Step 2.1's completion rule — commit existence required only under commit-per-task — the right
    reconciliation, or should a commit-per-story tick wait for the commit at the cost of AC1 on a
    HALTed run?
  3. Flush reachability: are there Phase-3/Phase-4 paths that reach a flush other than the two
    guarded ones (Step 3.1b itself and the HALT preamble)?

Not done (deliberately, flagged for the merge gate)

  • DoD "CLI (apps/pair-cli) updated" — unticked: n/a, no install/update/distribution surface
    was touched.
  • DoD "Verified on both manual implement and a supervised run" — unticked, and this is a real
    residual. The manual half is evidenced live on Breakdown-to-task feedback loop (close tasks + comment) #220 (four ticks + exactly one batched comment,
    5453972232). The supervised half has NOT been run live end-to-end. The "holds by
    construction" argument has been refuted three times, each time inside /implement where a
    composition argument cannot look: the flush unreachable on the supervised-default strategy;
    commit-per-story reporting nothing per task; and an ordinary tracker error able to HALT an
    unattended run. Each is now fixed and conformance-asserted with a mutation proof that the pin
    fires — mechanical evidence in place of the argument, not a replacement for the live pass. The
    live pass was not performed because a supervised iteration implements a real card and opens a real
    PR, side effects outside this story's scope. The merge gate decides whether it is required, or
    whether the supervised half is accepted unverified end-to-end.

Testing the Changes

git checkout feature/US-220-breakdown-task-feedback-loop
pnpm install
pnpm --filter @pair/knowledge-hub exec vitest run src/conformance/task-progress-feedback.test.ts
pnpm quality-gate

@rucka rucka added the risk:yellow Classification: medium risk tier label Aug 28, 2026
@rucka rucka self-assigned this Aug 28, 2026
@rucka rucka added the pr-state:to-be-reviewed PR state: awaiting review / gate label Aug 28, 2026
@rucka

rucka commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict

risk:yellow · cost:greenCHANGES-REQUESTED — the flush step is unreachable on the recommended commit-per-task path, and reachable twice on a HALT after it fired.

Open findings: 6.

PR: #468 · Author: rucka · Reviewer: independent reviewer agent · Date: 2026-08-28 · Story: US-220 · Type: feature

Classification matrix — per dimension
Dimension Tier Source Note
Service/domain criticality green tech/risk-matrix.md packages/knowledge-hub + guarded skill mirrors — Low
Change/diff risk yellow diff footprint 3 authored skills + 1 new KB guideline, each with its dataset/mirror pair
Business impact yellow subdomain class Collaborative Workflow (Core) — progress visibility
Security relevance green /pair-capability-assess-security markdown/KB only; no inputs, no secrets, no auth surface
Coupling balance green /pair-capability-assess-coupling no new edge — implement already writes to the PM tool

Tier = max(assessed) = yellow — confirms refinement-time classification.

Assessments

Security — Input validation

Verdict: green — no input surface: the diff is markdown/KB plus one read-only conformance test.

Security — Output handling

Verdict: green — the only rendered output is a PM comment body composed by the skill; no encoding surface introduced.

Security — Authentication

Verdict: green — writes ride the already-credentialed /pair-capability-write-issue path; no credential handling added.

Security — Authorization

Verdict: green — no access-control decision on the changed paths.

Security — Introduced vulnerabilities

Verdict: green — 0 introduced, 0 pre-existing.

Cost

Verdict: cost:green — no infra, no new dependency, no runtime.

Architecture (Coupling)

Verdict: green — one owner (guideline), one caller (/implement); /loop gains an explicit boundary against a second writer.

Bug fix — Red test before fix

Verdict: not applicable — not a bug fix.

Details

Findings by severity

Critical (must fix before merge)

  • none

Major (must fix before merge)

  • .claude/skills/pair-process-implement/SKILL.md:266 (and packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md:266) — Step 3.1's skip still routes to Step 3.2, jumping over the new Step 3.1b. Failure case: a 4-task story on commit-per-task; Step 2.8 ticks T1–T4 and queues 4 outcome lines; Phase 3 opens at Step 3.1, the check reads "Is the strategy commit-per-story?", the answer is no, and the instruction is literally "If commit-per-task, all commits already exist. Move to Step 3.2." → checkpoint → PR. The queue is never flushed and no progress comment is ever posted — AC2's whole deliverable is silent. This is not a corner: Step 1.3 line 131 labels commit-per-task "(recommended)", and .claude/workflows/pair-implement-batch.js:14 instructs supervised implementers to "COMMIT AFTER EVERY TASK", so the unattended path R4.6 exists for is exactly the path that loses the comment. The new suite cannot catch it: task-progress-feedback.test.ts:235-246 only asserts indexOf(3.1b) < indexOf(3.2), which a jump target defeats. Fix: Move to Step 3.1b. in the dataset source, regenerate the mirror, and add an assertion that no Phase-3 skip target names a step after 3.1b.
  • .claude/skills/pair-process-implement/SKILL.md:374 + :297 — the HALT preamble re-flushes an already-flushed batch, because Step 3.1b's guard is "Is the queue empty (no task completed or attempted this invocation)?" — a condition that stays false after a flush, since the tasks were still attempted. Failure case: commit-per-story, 3 tasks done → Step 3.1b posts the progress comment → Step 3.3 hits the listed HALT "Quality gate red inside /pair-capability-publish-pr" → the preamble says "flush the task-progress batch first (Step 3.1b's rendering and posting rules, unchanged)" → a second, near-identical progress comment on the same story in the same invocation. That is precisely the comment spam AC2 forbids and what the guideline calls out twice (task-progress-feedback.md:76 "Never a second comment", :115). Fix: make the flush drain the queue and gate on it — Step 3.1b item 1 "queue empty or already flushed this invocation", and the HALT preamble "flush … unless Step 3.1b already flushed".

Minor (must fix before merge — same bar as Major, just lower impact)

  • .pair/knowledge/…/task-progress-feedback.md:43 vs :46 — the diff check says "the diff must be exactly one line", while line 46 (and /implement Step 2.8 item 7) tells the caller to also tick DoD boxes "by the same rule". Failure case: T2 completes and factually satisfies DoD "Automated tests written and passing"; the caller patches both lines into one body; the diff check sees a two-line diff → patch-rejected → the write is abandoned and even the task's own tick is lost, reported as a feedback failure though nothing was wrong. Fix: state that each checkbox is its own diff-checked write (one changed line per write), or that the check admits N lines provided every one differs only in its checkbox marker.
  • apps/website/content/docs/developer-journey/execution.mdx:60"See the task-progress feedback guideline for the locator, the tick-only patch rule and the fallbacks" lands on a catalog row where "task-progress feedback (checklist ticks + one batched comment per run iteration)" is plain text, unlike its three siblings in the same row which link to /docs/concepts/canonical-states, /docs/concepts/pr-state-flow and /docs/concepts/definition-of-ready-and-done. Failure case: a reader wanting the locator/patch/fallback rules clicks, reaches the catalog table, and finds a parenthetical with no destination — the promised content exists nowhere on the docs site. Fix: link the catalog entry to a page carrying those rules, or reword the sentence to stop promising them.
  • packages/knowledge-hub/src/conformance/task-progress-feedback.test.ts:15-19 — the header states "Both the dataset source and the generated root mirror are asserted", but every wiring assertion (lines 219-278) reads the dataset copy only: implementMirror (line 212) is used once, at line 216, and the /loop + /write-issue mirrors are never read. Not a drift risk — src/tools/skill-md-mirror.ts guards full mirror equality — but a reader trusting the header will believe the root .claude/skills wiring is pinned here when it is not. Fix: reword to say the mechanism is asserted on both copies while wiring is asserted on the dataset source, mirror equality being skill-md-mirror's job.

Questions (informational, never blocking)

  • DoD "Verified on both manual implement and a supervised run" — the PR argues the supervised half holds by construction. Finding 1 is the counter-example: the missing flush sits precisely on the strategy supervised runs are told to use, and a single live supervised iteration would have surfaced it. After the fix, is one live /loop pass worth running before merge?
Positive feedback
  • Live evidence is real and checked: issue Breakdown-to-task feedback loop (close tasks + comment) #220 comment 5453972232 is exactly one D22-shaped batch, and the story's Task Breakdown carries - [x] T1..T4 in the non-canonical T3 — title rendering the locator table explicitly promises to tolerate — the locator's hardest claim is proven on the story itself.
  • The dataset↔mirror delta on the new guideline is exactly the documented /command rewrite (/implement/pair-process-implement, /write-issue/pair-capability-write-issue) and nothing else — verified by diff.
  • The ADL records the rejected alternatives with the reason each was rejected, including the tick-only /write-issue mode, so the caller-side diff check reads as a decision rather than an omission.
  • No competing writer left in the corpus: a sweep of .claude/skills finds no other skill instructing task-checklist ticks.
Functionality & requirements (AC coverage)
AC Status Evidence
1 — tick + progress comment on task completion partial ticks verified live on #220; the comment is unreachable on commit-per-task (Major 1)
2 — one batched comment per iteration, D22 partial format correct and asserted; violated by the double flush on HALT (Major 2)
3 — failure/skip recorded, item stays unticked met outcome vocabulary table + HALT queues failed
4 — no separate task issues met guideline "What never happens"; asserted
Edge: item not found / ambiguous met not-found / ambiguous, never guess-tick
Edge: concurrent edit conflict met fresh read + re-run locator + one retry + comment-only
Edge: PM write failure never blocks met Optional composition + "reported, not raised"
Testing & quality gates
  • Ran in a detached worktree at b83388f2: vitest run src/conformance/task-progress-feedback.test.ts56 passed (56).
  • Coverage gap: no assertion pins the Phase-3 control flow into Step 3.1b, which is what let Major 1 through.
  • Quality gates: PASS as reported by the author; not independently re-run (the throwaway worktree has no installed deps).
Adoption compliance
  • Degradation level: 1.
  • No new dependency; guideline placed under the PM-tool guideline family and indexed in README.md + .pair/llms.txt (correct alphabetical/date position).
  • ADL present for the design decision; the "no dataset mirror for ADLs" convention is cited with its precedent.
Tech debt
  • None promoted. All findings above are fixable in this PR.
Documentation
  • Guideline, execution journey page, guidelines catalog, llms.txt and the ADL all updated — one dead-ending link (Minor 2).
Performance & deployment
  • No runtime code; no hot path, no migration, no rollout concern.

rucka added a commit that referenced this pull request Aug 28, 2026
…st once

Review round 1 on PR #468.

- Step 3.1's commit-per-task skip targeted 3.2, jumping over the 3.1b flush:
  the recommended (and supervised-default) strategy posted no comment at all.
  Skip now targets 3.1b; new conformance assertion rejects ANY Phase-3 skip
  whose target ranks after 3.1b (heading order cannot see a jump).
- Step 3.1b drains the queue and guards on "empty OR already flushed"; the
  HALT preamble flushes unless 3.1b already did — the Step 3.3 HALTs fire
  after the post, so they were producing a second comment per iteration.
- Guideline: one write per checkbox — a task ticking its item AND a DoD box
  is two read-patch-write cycles, not a two-line diff the check rejects.
- execution.mdx no longer promises locator/patch/fallback detail behind a
  catalog link that does not host it; it states the three rules inline.
- Test header: mechanism asserted on both copies, wiring on the dataset,
  mirror equality delegated to skill-md-mirror.

Refs: #220
rucka added a commit that referenced this pull request Aug 28, 2026
…line it pins

Review round 2 on PR #468.

- The anti-jump detector read raw markdown (`Move to (?:Step|Phase)`) against a
  file written `Move to **Step 3.1b**`: it matched nothing before the flush, so
  the assertion passed on an empty set for ANY target. Emphasis is stripped
  first, and a mutation test restores the verbatim round-1 bug and requires the
  detector to report it.
- Step 2.8 item 2 short-circuited commit-per-story to Step 2.1 BEFORE the
  tick-and-queue: a 4-task story red on T3 queued only the failure and left
  T1/T2 unticked. Item 2 now routes through items 7-8; assertion pins that the
  queue site is not inside a strategy branch.
- Step 3.1 item 7 is catch-up only and scoped to THIS invocation, so a re-run
  that found everything done reaches 3.1b with an empty queue (no duplicate
  comment); the guideline says the same on both the patch and the batch rule.
- Step 2.1 gains the producing call site for `skipped` (unmet dependency,
  deferral): queued with its reason, not HALTed as `failed`, not silent.
- Guideline lead-in said "Three properties" over four; the count is now
  asserted against the list length rather than spelled by hand.

Refs: #220
@rucka

rucka commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

In reply to the first-review comment (5454094577).

Escalating — review<->fix loop round 4, human decision needed

Three prior fix rounds converged on findings from the first review; round 4 (review of 608b77d2) surfaced three new findings that don't have a clean auto-fix and are being escalated rather than round-tripped again. Full detail (mutation proofs, evidence, diffs per round) lives in the working log .pair/working/reviews/220.md in the authoring worktree — this comment is the human-facing summary.

Rounds so far

Round 1 (review of b83388f2, fixed in 67a74098) — 2 Major + 3 Minor + 1 Questions. Major: Step 3.1's skip jumped over the new flush step (Step 3.1b), so the progress comment was unreachable on the recommended commit-per-task path; and the HALT preamble re-flushed an already-posted batch. Both fixed with conformance assertions + mutation proof. 3 Minor doc/test fixes. The Questions item (DoD "verified on a supervised run") was not run live — stated at the merge gate instead, per the reviewer's second option.

Round 2 (review of 67a74098, fixed in 6f86947b) — 2 Major + 3 Minor + 1 Questions (repeat). Major: the anti-jump detector was blind to bold markdown (**Step 3.2** slipped past the regex); and commit-per-story never ticked or queued the task at all. Both fixed and mutation-proved. 3 Minor: property count assertion, re-tick scoping, skipped call site. Questions item again deferred to the merge gate (same reasoning as round 1 — a live /loop pass has real side effects outside a fix round's mandate).

Round 3 (review of 6f86947b, fixed in 608b77d2) — 1 Major + 3 Minor + 1 Questions (repeat) + 1 new Questions. Major: /write-issue HALTs (not-found, membership, tracker error) were propagating out into the tick instead of being carve-out'd, fixed with a new $on-failure: report argument + Step 8b, scoped to the three tracker-side failures only. 3 Minor fixes. New Questions item (unreported-loss window on a batch lost with its session) answered by stating the consequence + an Alternatives-Considered entry rather than engineering it away. The recurring DoD-verification Questions item deferred again, same reasoning.

Across all three rounds, every recommendation was taken except where the PR argued a documented alternative (see the log for the per-round "Divergences from the recommendation" — each has a stated reason).

Round 4 — still open (escalated, not fixed)

  • [Minor] packages/knowledge-hub/dataset/.pair/knowledge/guidelines/collaboration/project-management-tool/task-progress-feedback.md:47 (with :29 and :96) and .skills/process/implement/SKILL.md:253 + the .claude mirrors — DoD checkbox ticking is ordered by Step 2.8 item 7 ("by the same rule") but the guideline's only locator is scoped to task-ID lines inside ## Task Breakdown and explicitly forbids matching on text/title — a DoD box has neither. Three concrete failure modes are traced in the finding: silent drop (locator finds zero matches, nothing gets ticked, contradicting the instruction that mandated it), guess-tick (falls back to the forbidden text match — the path this very PR's DoD boxes took), and an invisible failure (a write-failed under the new $on-failure: report has no per-task line in the batch to carry it, so the run reports green while the DoD box silently stays unticked). Recommendation on the table: define a DoD-box locator explicitly (verbatim line text within ## Definition of Done Checklist, exactly one match or not-found/ambiguous), and state that its outcome rides in the <details> of the task whose work satisfied it.

  • [Questions] packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md:225 (Step 2.8 item 2) vs :143 (Step 2.1's completion rule) — on commit-per-story the tracker tick now lands before any commit exists (round 2's fix), and Step 2.1's completion check requires a commit only under commit-per-task. A run that HALTs between the tick (Step 2.8) and the commit (Step 3.1), or whose worktree is discarded, leaves the board asserting a task done over a branch with zero commits — and resume trusts the tick alone. This trade was made deliberately in round 2 (the alternative loses AC1 on that HALT path) but its board-facing half isn't stated anywhere a reader would check. Question for the human: confirm the trade as-is (and state it once in the guideline), or require the commit on both strategies and accept an unticked HALT instead.

  • [Questions] task-progress-feedback.md:58 (the format headline) vs :98**Task progress — N of M tasks this iteration** defines N and M only by example, not by rule. On a partial batch (a fail or skip present) two readings diverge: N = lines queued this batch, or N = tasks that actually landed ticked. The intended reading is derivable from the existing examples (N = queued lines, M = tasks in the breakdown) but is never asserted as a rule anywhere in the corpus.

Convention for continuing this cycle

Any further rework or re-review on this story from here — including manual, out-of-band rounds — should be appended to .pair/working/reviews/220.md in the authoring worktree, not posted as a new standalone PR comment. The next orchestrated run on this story resumes this same cycle from that log; its eventual convergence will synthesize one final remediation comment and minimize this one (and the first-review comment stays visible as the anchor throughout).

Note: that working log is an untracked file living only in the persistent authoring worktree ../pair-worktrees/220 — it is not part of the branch/PR diff. That worktree must be preserved until merge; if it's pruned or recreated, the round-by-round audit trail above is lost (this comment and the first-review comment remain on the PR either way, and the first-review comment's presence still prevents a duplicate first review on the next run).

Not merging. Awaiting human decision on the two Questions items and the DoD-locator gap above.

@rucka rucka left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

risk:yellow · cost:greenAPPROVED

Open findings: 0. All Major/Minor findings from prior rounds are resolved and verified on the current head 80dea663dce822db6ced0e691355a165ef95db0e.

PR: #468 · Story: #220 · Author/reviewer: rucka · Date: 2026-08-30

Classification

Dimension Assessment Result
Criticality shared delivery knowledge and review workflow yellow
Change risk command/documentation contract, no production runtime path yellow
Business impact developer workflow correctness yellow
Security no sensitive-data, auth, or trust-boundary change green
Coupling existing knowledge-hub components only balanced
Cost no billable/external-resource surface green

Existing labels remain correct: risk:yellow, cost:green.

Findings

Critical

None.

Major

None.

Minor — resolved

Finding Resolution Verification
Definition-of-Done locator was implicit while task-ID lookup was explicit Added a criterion-anchored, ambiguity-safe locator to source guidance and the shipped dataset mirror TDD RED (2 failing tests) → GREEN; conformance suite 4,993 passing

Questions / residual scope

The story's supervised live-run DoD remains intentionally unexecuted: it requires a real external card/PR and is explicitly outside this PR's side-effect-free verification scope. This is recorded, not a Major/Minor finding.

Review evidence

Area Result
Functionality / AC Covered; task and DoD lookup contracts now reject missing or ambiguous targets without a write
Test-first remediation Red test reproduced the omitted DoD locator; green implementation retained regression coverage
Target tests @pair/knowledge-hub: 49 files, 4,993 tests passed
Quality gate pnpm quality-gate passed on exact head
CI build, preview, secret scan, smoke: passed
Security Green — no new input, output, authorization, or vulnerability finding
Adoption Level 1 conformant; no dependency, migration, or undeclared decision
Debt None introduced
Documentation Source guideline and packaged dataset mirror are synchronized
Performance / deploy No runtime hot path, migration, or deployment impact

Why prior reviews kept finding issues

Each remediation covered the reported path but not its adjacent contract boundary. Here, task-ID lookup was tested while the similar DoD lookup remained prose-only. The current tests assert both lookup contracts and their no-guess/no-write failure behavior, creating the required fixed point rather than relying on prose symmetry.

@rucka rucka added pr-state:ready-to-merge PR state: gates green + review approved and removed pr-state:to-be-reviewed PR state: awaiting review / gate labels Aug 30, 2026
@rucka
rucka force-pushed the feature/US-220-breakdown-task-feedback-loop branch from 80dea66 to 8666322 Compare September 2, 2026 05:37
rucka added a commit that referenced this pull request Sep 2, 2026
…st once

Review round 1 on PR #468.

- Step 3.1's commit-per-task skip targeted 3.2, jumping over the 3.1b flush:
  the recommended (and supervised-default) strategy posted no comment at all.
  Skip now targets 3.1b; new conformance assertion rejects ANY Phase-3 skip
  whose target ranks after 3.1b (heading order cannot see a jump).
- Step 3.1b drains the queue and guards on "empty OR already flushed"; the
  HALT preamble flushes unless 3.1b already did — the Step 3.3 HALTs fire
  after the post, so they were producing a second comment per iteration.
- Guideline: one write per checkbox — a task ticking its item AND a DoD box
  is two read-patch-write cycles, not a two-line diff the check rejects.
- execution.mdx no longer promises locator/patch/fallback detail behind a
  catalog link that does not host it; it states the three rules inline.
- Test header: mechanism asserted on both copies, wiring on the dataset,
  mirror equality delegated to skill-md-mirror.

Refs: #220
rucka added a commit that referenced this pull request Sep 2, 2026
…line it pins

Review round 2 on PR #468.

- The anti-jump detector read raw markdown (`Move to (?:Step|Phase)`) against a
  file written `Move to **Step 3.1b**`: it matched nothing before the flush, so
  the assertion passed on an empty set for ANY target. Emphasis is stripped
  first, and a mutation test restores the verbatim round-1 bug and requires the
  detector to report it.
- Step 2.8 item 2 short-circuited commit-per-story to Step 2.1 BEFORE the
  tick-and-queue: a 4-task story red on T3 queued only the failure and left
  T1/T2 unticked. Item 2 now routes through items 7-8; assertion pins that the
  queue site is not inside a strategy branch.
- Step 3.1 item 7 is catch-up only and scoped to THIS invocation, so a re-run
  that found everything done reaches 3.1b with an empty queue (no duplicate
  comment); the guideline says the same on both the patch and the batch rule.
- Step 2.1 gains the producing call site for `skipped` (unmet dependency,
  deferral): queued with its reason, not HALTed as `failed`, not silent.
- Guideline lead-in said "Three properties" over four; the count is now
  asserted against the list length rather than spelled by hand.

Refs: #220
rucka added a commit that referenced this pull request Sep 3, 2026
…st once

Review round 1 on PR #468.

- Step 3.1's commit-per-task skip targeted 3.2, jumping over the 3.1b flush:
  the recommended (and supervised-default) strategy posted no comment at all.
  Skip now targets 3.1b; new conformance assertion rejects ANY Phase-3 skip
  whose target ranks after 3.1b (heading order cannot see a jump).
- Step 3.1b drains the queue and guards on "empty OR already flushed"; the
  HALT preamble flushes unless 3.1b already did — the Step 3.3 HALTs fire
  after the post, so they were producing a second comment per iteration.
- Guideline: one write per checkbox — a task ticking its item AND a DoD box
  is two read-patch-write cycles, not a two-line diff the check rejects.
- execution.mdx no longer promises locator/patch/fallback detail behind a
  catalog link that does not host it; it states the three rules inline.
- Test header: mechanism asserted on both copies, wiring on the dataset,
  mirror equality delegated to skill-md-mirror.

Refs: #220
@rucka
rucka force-pushed the feature/US-220-breakdown-task-feedback-loop branch from 8666322 to f910723 Compare September 3, 2026 19:52
rucka added a commit that referenced this pull request Sep 3, 2026
…line it pins

Review round 2 on PR #468.

- The anti-jump detector read raw markdown (`Move to (?:Step|Phase)`) against a
  file written `Move to **Step 3.1b**`: it matched nothing before the flush, so
  the assertion passed on an empty set for ANY target. Emphasis is stripped
  first, and a mutation test restores the verbatim round-1 bug and requires the
  detector to report it.
- Step 2.8 item 2 short-circuited commit-per-story to Step 2.1 BEFORE the
  tick-and-queue: a 4-task story red on T3 queued only the failure and left
  T1/T2 unticked. Item 2 now routes through items 7-8; assertion pins that the
  queue site is not inside a strategy branch.
- Step 3.1 item 7 is catch-up only and scoped to THIS invocation, so a re-run
  that found everything done reaches 3.1b with an empty queue (no duplicate
  comment); the guideline says the same on both the patch and the batch rule.
- Step 2.1 gains the producing call site for `skipped` (unmet dependency,
  deferral): queued with its reason, not HALTed as `failed`, not silent.
- Guideline lead-in said "Three properties" over four; the count is now
  asserted against the list length rather than spelled by hand.

Refs: #220
@rucka
rucka force-pushed the main branch 4 times, most recently from 454a6ab to 3d1d33e Compare September 13, 2026 15:52
- new KB guideline task-progress-feedback.md: scope (one mechanism, /implement the only caller), task-ID anchored locator (tolerant renderings, exactly-one match, never guess-tick), tick-only diff-checked patch (never unticks)
- conformance guard over dataset + generated mirror (16 assertions)
- Task: T1 — Checklist locator + body patcher (task-ID anchored, tick-only edits)

Refs: #220
…ocabulary

- batching section: run iteration = one /implement invocation, flush once incl. early exit, empty batch posts nothing, never a second comment
- D22 format: headline + one line per task, everything longer in <details>
- closed outcome set (ticked/failed/skipped/not-found/ambiguous/patch-rejected/write-failed) with the per-outcome checklist effect — failure and skip stay unticked
- Task: T2 — Comment batcher (one per iteration, D22 format) + failure/skip recording

Refs: #220
- implement: /write-issue as an OPTIONAL composed skill, Step 2.8 ticks + queues per task, new Step 3.1b flushes one batched comment before the checkpoint hand-off, HALT flushes on the way out, Progress row in the output
- write-issue: composition interface for /implement — write mode (caller-patched full body) for the tick, comment mode for the batch, neither failure load-bearing
- loop: boundary — never posts its own per-task progress comments; the supervised path inherits implement's loop through implement-batch
- skill versions bumped (implement 0.7.0, write-issue 0.10.0, loop 0.1.1)
- Task: T3 — Wiring into implement (manual + supervised paths)

Refs: #220
- guideline: writes confirmed by a read (never an exit status), body-conflict retry from a FRESH read with the locator re-run, exactly one retry, comment-only fallback, PM write failure never blocks the run
- "What never happens": no task issues, no other section rewritten, no board state, no untick
- ADL: one mechanism owned by implement, batched per invocation (5 alternatives weighed)
- docs site: execution journey gains a Progress Feedback section; guidelines catalog lists it
- conformance suite now 56 assertions over dataset + mirror + skills + docs
- Task: T4 — Conflict/failure fallbacks + tests + docs site

Refs: #220
…st once

Review round 1 on PR #468.

- Step 3.1's commit-per-task skip targeted 3.2, jumping over the 3.1b flush:
  the recommended (and supervised-default) strategy posted no comment at all.
  Skip now targets 3.1b; new conformance assertion rejects ANY Phase-3 skip
  whose target ranks after 3.1b (heading order cannot see a jump).
- Step 3.1b drains the queue and guards on "empty OR already flushed"; the
  HALT preamble flushes unless 3.1b already did — the Step 3.3 HALTs fire
  after the post, so they were producing a second comment per iteration.
- Guideline: one write per checkbox — a task ticking its item AND a DoD box
  is two read-patch-write cycles, not a two-line diff the check rejects.
- execution.mdx no longer promises locator/patch/fallback detail behind a
  catalog link that does not host it; it states the three rules inline.
- Test header: mechanism asserted on both copies, wiring on the dataset,
  mirror equality delegated to skill-md-mirror.

Refs: #220
…line it pins

Review round 2 on PR #468.

- The anti-jump detector read raw markdown (`Move to (?:Step|Phase)`) against a
  file written `Move to **Step 3.1b**`: it matched nothing before the flush, so
  the assertion passed on an empty set for ANY target. Emphasis is stripped
  first, and a mutation test restores the verbatim round-1 bug and requires the
  detector to report it.
- Step 2.8 item 2 short-circuited commit-per-story to Step 2.1 BEFORE the
  tick-and-queue: a 4-task story red on T3 queued only the failure and left
  T1/T2 unticked. Item 2 now routes through items 7-8; assertion pins that the
  queue site is not inside a strategy branch.
- Step 3.1 item 7 is catch-up only and scoped to THIS invocation, so a re-run
  that found everything done reaches 3.1b with an empty queue (no duplicate
  comment); the guideline says the same on both the patch and the batch rule.
- Step 2.1 gains the producing call site for `skipped` (unmet dependency,
  deferral): queued with its reason, not HALTed as `failed`, not silent.
- Guideline lead-in said "Three properties" over four; the count is now
  asserted against the list length rather than spelled by hand.

Refs: #220
- /write-issue: `$on-failure` arg + Step 8b — the three tracker-side
  HALTs (Step 7 not-found, Step 7b membership, Step 8 error) return
  `not-found`/`membership-unconfirmed`/`write-failed` to the caller;
  carve-out written at each site AND on the HALT Conditions rows, which
  is where an executing agent reads. Steps 1/3/6 still HALT.
- /implement: `skipped` queued at most once per invocation (2.1 re-scans
  from the top after every task); Idempotent item 4 no longer says
  "Skips them" over the reserved outcome.
- guideline: board-inertness scoped to the STATE field + names the
  transport's membership beats; the lost-with-its-session batch stated
  as a tradeoff. ADL Consequences + Alternatives updated.
- suite 70 -> 86, every new pin mutation-proved.

- Task: T4 — Conflict/failure fallbacks (review round 3)

Refs: #220
Define a fail-closed DoD locator and retain task evidence.\n\nRefs: #220
@rucka
rucka force-pushed the feature/US-220-breakdown-task-feedback-loop branch from f910723 to 31cbc8d Compare September 13, 2026 16:48
@rucka

rucka commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator Author

Post-rebase re-review + remediation — PR #468 feature/US-22031cbc8dd

Context: head 31cbc8dd rebased today onto main 3d1d33e6 (post-#480/#481). Conflicts only on shared history already in main, no substantive hunk for #220 — verified with git diff 8666322d..31cbc8dd --stat (only .claude/* workflows, format.yml, ADL from main) and three-dot origin/main...branch identical (15 files, +1339/−51).

Re-review /pair-process-review $pr=468 on 31cbc8dd (6 phases, no Phase 6)

  • Phase 1 classify: risk:yellow confirmed (max generic+yellow), cost:green.
  • Phase 2.1 verify-quality: gh pr checks 468 5/5 SUCCESS (build 5m13s, format, preview, smoke, secret-scan PASS) — no cap.
  • Phases 2.2-2.7: task-progress-feedback.md/write-issue $on-failure: report/ Step 3.1b — no Design Rule violations, ADL present, Security green (0 introduced, tick-only patch does not touch authz), Cost green, Coupling not assessed, red-test n/a (feature).
  • Phase 3 verify-adoption L1 and Phase 4 verify-done/analyze-debt: DoD 1 open item declared at merge gate (Verified on both manual implement and a supervised run — supervised half never run live, residual wiring, needsHumanDecision), debt 0 blocking.
  • Verdict: risk:yellow · cost:greenAPPROVED — 0 Major / 0 Minor (1 Question DoD declared, non-blocking). No fix required — zero-cost rebase for this card.

Updated artifacts

  • /.pair/working/pr-analyses/468-task-progress-feedback-loop.mdupdated to 31cbc8dd (header + §8, merge-base 3d1d33e6, real delta verified).
  • This comment is the single remediation report for the current head. Previous APPROVED review on 80dea663 consulted only as reference.

Merge: Phase 6 not executed. PR ready for manual merge (green gate, pr-state:ready-to-merge).

@rucka
rucka merged commit 6e37df9 into main Sep 14, 2026
5 checks passed
@rucka
rucka deleted the feature/US-220-breakdown-task-feedback-loop branch September 14, 2026 08:58
rucka pushed a commit that referenced this pull request Sep 14, 2026
…#468

Rebase 6e37df9 lost the marker when resolving version conflict
(0.7.4 vs 0.7.0). Restore executable marker + short gate text so
checkStepMarkers passes on both dataset and mirror.

Refs: #251
rucka added a commit that referenced this pull request Sep 14, 2026
…elist) (#467)

* [#251] test: process-profile guard + reference resolver (RED)

- skills-conformance-check gains the catalogue<->corpus binding (both
  directions), the process-step marker check, built-in profile validation and
  resolveProcessProfile — the executable statement of the schema; fail-closed on
  a missing catalogue
- 21 white-box unit tests incl. the six way-of-working states (AC1/3/4/5/9/10)
- process-profile.test.ts: the prose contract a CLI cannot assert (schema HALTs,
  gate convention, WoW section, /next's resolution step)
- RED: skills:conformance FAIL (1 violation), process-profile 42/44 failing
- Tasks: T-7, T-8 (test-first half)

Refs: #251

* [#251] feat: KB step catalogue + process-profile schema and built-ins

- step-catalogue.md: 12 steps, each with a stable id, its how-to and its
  executable (both nullable) and any-of prerequisites. The three asymmetries
  (04/05 retired guides -> capabilities, brainstorm with no guide) are ROWS, not
  conditionals; a "not a step" table draws the boundary the profile stops at
- process-profiles.md: schema, default/poc built-ins, the five HALT cases and
  the one reported-not-fatal inconsistency, plus who reads the profile
- corpus binding now green: 9 how-to guides and 10 process skills all catalogued
- Tasks: T-1, T-2

Refs: #251

* [#251] feat: process-profile-gate convention — direct invocation vs composition

- new skill-conventions doc: the gate warns+confirms ONLY on direct invocation;
  a composed disabled step degrades through graceful-degradation scenario 3
  (optional composed skill not installed), never a prompt
- the composing skill applies the check BEFORE composing, so the composed
  skill's own gate cannot fire on a question the user never triggered
- HALT cases stay HALTs: a typo must not resolve to "disabled" and be waved
  through by a confirmation
- conventions index gains the row
- Task: T-5

Refs: #251

* [#251] feat: `## Process Profile` section in way-of-working (adoption side)

- shipped adoption template: optional section, field table, the omitted-means-
  default rule, the manual-path note, the three HALTs and two worked examples
  (poc, custom whitelist); points at the KB schema rather than restating it
- this repo's own adoption: section present, nothing declared — pair runs the
  full process, same shape as `## Git Workflow`
- the gate now resolves the SHIPPED TEMPLATE through resolveProcessProfile, so a
  template that ships an unreadable section fails CI
- Task: T-3

Refs: #251

* [#251] feat: the 12 step skills declare their step id and point at the gate

- `## Process Profile` section at each skill's invocation entry point, carrying
  the declared `<!-- process-step: id=... -->` marker and the one-line pointer;
  no gate logic is restated per skill
- the 5 skills that COMPOSE a step (bootstrap, brainstorm, plan-epics,
  plan-tasks, refine-story) say so explicitly: the check runs before composing
  and a disabled step degrades as not-installed — this is AC7, the case most
  likely to be built as a prompt
- map-subdomains/map-contexts are in the $approval family, so their round
  carries `kind=gate; auto=halt`; the convention states that resolution once
- minor version bump on all 12 (new gate step, per skill-conventions/README)
- skills:conformance PASS — 44 skills
- Task: T-6

Refs: #251

* [#251] feat: /next resolves the process profile and never proposes a disabled step

- new Step 0.5, before the cascade: read way-of-working's `## Process Profile`,
  resolve against the catalogue, carry the enabled step set into Steps 2-4
- absent section => `default` => the cascade runs unchanged (AC1)
- the four HALTs (unknown name, unknown id, empty whitelist, whitelist under a
  built-in), with the two messages deliberately distinct (AC5/AC10)
- a disabled row is SKIPPED, not errored, so enabled steps chain across the gaps
  (AC4); the row -> step-id mapping is a table, not row-wording inference
- prerequisite consistency reported with the minimal fix, never repaired (AC9)
- rows 7 and 12-16 propose capabilities that are not steps: never filtered
- output gains a Profile line; degradation bullet states no-section is the
  zero-config default, not a degradation; version 0.5.1 -> 0.6.0
- Task: T-4

Refs: #251

* [#251] docs(website): process-profile schema + examples

- concepts/adoption-files: `## Process Profile` subsection under
  way-of-working.md — the three profiles, both worked examples, the "unit is the
  step" point that makes the no-skills manual path work, the three places a
  disabled step is met, and the validation rules
- reference/pair-next: the profile is a SECOND narrowing, orthogonal to
  --root/--filter (items vs steps); no section => default; skipped not errored
- no new page, so CP5's asserted page list is unchanged
- Task: T-9

Refs: #251

* [#251] chore: mirrors regenerated, gate refactor, brainstorm disclosure

- `pair update` run: `.claude/skills/**`, `.pair/knowledge/**` and `.pair/llms.txt`
  regenerated from the dataset sources
- the 12 per-skill deltas compressed to the ONE line the convention asks for
  (~460 B, down from ~900); brainstorm hits its progressive-disclosure byte
  budget, so its half of the convention is disclosed to the sibling that already
  owns "a composition is missing" (degradation.md) — the budget's own instructed
  remedy, budget NOT raised (mirror 28,643 B of 28,672)
- checkStepMarkers therefore resolves the convention POINTER over the skill's
  whole directory (the marker stays in SKILL.md) — the mirror of the rule
  checkApprovalSignalInSubDocs already applies; unit test added
- gate module split for lint limits (Claims ledger, checkCatalogueRow /
  checkCatalogueOrphans / checkUniqueStepIds, resolveCustomWhitelist,
  checkProcessStepCorpus) — no behaviour change, 124 unit tests green
- "epic-level AC4" removed from next's SKILL.md: story-local marker ban
- Task: T-10

Refs: #251

* [#251] docs: ADR-024 (the unit is the step) + ADL on the marker/pointer split

- ADR-024: why the profile whitelists a STEP id and never a representation —
  the measured asymmetry (9 guides vs 10 process skills, DDD mapping being
  capabilities per ADR-012, brainstorm having no guide) makes the epic's own poc
  case inexpressible on either representation alone; any-of prerequisites and
  the catalogue-as-scope-boundary recorded as part of the decision
- ADL: a convention's MARKER belongs to the entrypoint, its POINTER may be
  disclosed to a sibling — how brainstorm honours the corpus-wide obligation
  inside its byte budget, and why the budget was not raised
- llms.txt regenerated (indexes both records)

Refs: #251

* [#251] fix: review round 1 — reader HALTs on a shape it can't read, gate binds the mirror + manual path

Round 1 findings, all 8 resolved in place.

- parseWowProfileSection: detect the KEY loosely (bold/unbackticked), accept
  the VALUE strictly; a detected key with no readable value HALTs with the
  schema shape instead of resolving to `default` — the silent WIDENING the
  review found (`- \`profile\`: poc` -> 12 steps, no halt).
- sectionOf: line-start heading outside fences, `null` when absent — a prose
  cross-reference or a fenced sample no longer becomes the section.
- resolveCustomWhitelist: no `whitelist` key != empty whitelist, two messages.
- checkStepMarkersInMirror + checkManualPathEntrypoint, both wired into
  `skills:conformance`: the installed `.claude/skills/**` copy and AGENTS.md's
  manual flow are now governed; extractProfileExamples resolves every shipped
  worked example through the real reader.
- dataset/AGENTS.md: manual flow gets a profile step before "identify your task"
  (mirrors regenerated). brainstorm degradation.md drops the `$approval` clause.
  step-catalogue heading + /next row->step table order. `custom` example is now
  prerequisite-clean.

ADL: a config reader detects loosely and accepts strictly; a shipped mirror is
a governed copy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* [#251] fix: review round 2 — residue decides readability, heading read as loosely as the keys, fallback filtered

- llms.txt regenerated: the round-1 ADL was missing from the index (RED gate)
- parseWowProfileSection: readability decided on the RESIDUE, not token count —
  a partially backticked whitelist HALTs instead of dropping the bare ids;
  a `profile` line with >1 value HALTs instead of taking values[0]
- isWowProfileHeading: equality on normalized heading text, so a decorated
  `## Process profile` no longer widens the profile to the full 12 steps
- /next: enabled set carried into Steps 2–5; Step 5 fallback names only enabled
  steps and proposes /brainstorm when the profile leaves no reachable input

13 tests RED first, then 203 green. ADL extended in place (same decision, wider
surface). Refs: #251

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* [#251] fix: review round 3 — the declaration SITE is read too (duplicate section, heading level)

- profileSectionProblems(): a second `## Process Profile` section HALTs (only the
  first was read, the later declaration took effect nowhere), and a heading at any
  level other than `##` HALTs instead of being neither a section nor a report
- separate scan, NOT a widening of sectionOfWhere's `^##` predicate: that predicate
  also decides where a section ENDS, and an `###` sub-heading is legitimately inside
  `## The Catalogue` / `## Built-in Profiles` / `## Quick Start Process`
- ProfileDeclaration.sectionHalts carries them; resolveProcessProfile checks WHERE
  the declaration sits before WHAT it says

6 tests RED first, then 216 green. KB error table, /next Step 0.5 and both website
pages carry the two new normative cases; ADL extended in place. Refs: #251

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* [#251] fix: review round 4 — the KEY and its MARKER are read too, and the TEMPLATE's examples are

- extractProfileExamples: a fence with `profile`/`whitelist` key lines IS an example; the
  shipped WoW template writes its heading outside the fence, so none of its examples were
  gate-checked while the PR claimed they were. Corrupting one now exits 1.
- parseWowProfileSection: a key declared on two lines HALTs (was last-wins, silent, and
  order-dependent). Marker class widened to `-`/`*`/`+`; a bullet-less or ordered-list
  backticked key is DETECTED and HALTs instead of being invisible text.
- process-profile-gate.md: the normative snippet is the `/refine-story` delta verbatim,
  pinned by a conformance test.
- CLI PASS line enumerates this story's checks; `/next` 0.6.2 -> 0.6.0 (one minor bump).
- KB schema + `/next` Step 0.5 + both website pages carry the two new normative rules; ADL
  extended in place.

Refs: #251

* [#251] fix: review round 5 — the reader reads CommonMark, not lines of text

CRLF file resolved to `default` with zero halts (every guard silent at once);
titled/`~~~` fences hid worked examples from the gate while the section parser
skipped them; `~~~`/indented examples read as the real declaration; closed-ATX,
≤3-space-indented and setext headings neither matched nor reported; sweep
covered 2 of 5 shipped surfaces; example errors named the fallback profile;
ADR-024's H1 carried no number.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 6 — a key is ONE line at the top level, and a truncated document is not read

Five reader holes, all silent, all in the widening or narrowing direction:

- a whitelist WRAPPED onto a second line was truncated to the first line's ids
  (residue check erased the trailing `,`, continuation line discarded): 8 ids in,
  4 enabled, zero halts. Dangling separator + lazy continuation now HALT.
- a key indented by 4 spaces or a tab was skipped as an indented code block, though
  it is equally a sublist item — 2 spaces read, 4 spaces `default`/12. Ambiguous
  now HALTs.
- scanFences tracked the fence CHARACTER but not its LENGTH, so an inner ``` closed
  an outer ```` and its example escaped into declaration space.
- a `## Process Profile` inside `<!-- -->` counted as a real section.
- an UNTERMINATED fence above the section made the whole section invisible.

scanProfileDocument replaces the raw line scan: fences by char AND length, HTML
comment spans masked, an unclosed delimiter reported and HALTed.

Prose + mirrors + docs site + ADL extended in place.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 7 — a file the gate names as checked is READ, and a HALT hands out no step set

- gate: both way-of-working files resolved as DECLARATIONS, not only swept for
  fenced examples. This repo's own carries no example, so zero checks applied to
  it while the PASS line named it: `- `profile`: `pocc`` shipped PASS/exit 0.
- resolveProcessProfile returns a discriminated union: a HALT arm has no
  `enabled`, so the widening a negligent caller could read is unwritable.
- the 4 composers name the profile AT the composition beat + in degradation,
  as brainstorm already did; /next repeats the profile filter under Step 2.
- off-marker comment corrected: a doc TABLE row is not a declaration and must
  not be (it would HALT the shipped template) — pinned by a unit case.
- STEP_MARKER pinned on behaviour; docs error prose → scannable table.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 8 — a quotation is not a declaration, and a step is named once

- A key inside a blockquote HALTs: `> - `profile`: `poc`` matched neither key
  pattern (`>` is not whitespace), so it resolved to `default` / 12 steps with
  zero halts — the silent widening. A documentation TABLE row stays the
  deliberate opposite (no declaration, no HALT): the schema and the shipped
  template document the keys in one, so matching it would redden the gate on its
  own governing files. Both halves now stated in schema, template, /next 0.5 and
  both docs pages, pinned in both directions.
- The other arm: a blockquote OPENS a block, so blockquoted prose under a key
  line is no longer read as that value's lazy continuation (it HALTed a readable
  declaration as "spilled").
- A step id repeated in a `custom` whitelist HALTs naming it, never deduped: the
  same mistake HALTs one rung up when it is the KEY that repeats, and unread it
  emitted the id's prerequisite warning twice byte for byte with `enabled`
  carrying the duplicate.
- ADL 2026-08-28-a-config-reader-… extended in place (8th), with both rejected
  alternatives (dedupe; treat the blockquote as documentation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 9 — the key's CASE is its spelling, the value's is not

- All three key patterns were case-sensitive while the HEADING one level up is
  not: `- `Profile`: `poc`` resolved to `default` / 12 steps, zero halts, zero
  warnings — byte-identical to writing nothing (the silent widening). Worse,
  `custom` + `- `Whitelist`: `implement`` HALTed with "declares no `whitelist`"
  about a line visibly in the file — the anti-pattern the schema's own table
  writes down.
- Detection is now case-insensitive on all three patterns and the capture is
  canonicalized once (`canonicalKey`), so two spellings of one key are one key
  declared twice and every message prints the canonical name. Accepted, not
  HALTed: case is a decoration like bold/missing backticks, all honoured. The
  rejected MARKER shapes (off-marker, blockquote) keep their HALT in any case;
  the VALUE stays strict — `POC` is still an unknown profile name.
- Schema error table, adoption template, /next 0.5 and both docs pages state the
  rule; ADL 2026-08-28-a-config-reader-… extended in place (9th) with the
  rejected alternative (route the case variant to unreadableShapeHalt).
- The template's corruption test now anchors on the FENCE: its first-occurrence
  replace hit the new prose bullet, leaving the worked example intact and the
  test green whatever the gate did.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 10 — two errors on one line compose, and a file the gate cannot find is not "clean"

- rejected-marker patterns: backticks optional behind a list marker, required
  only marker-less. `1. profile: poc` / `> - profile: poc` resolved default/12
  with zero halts while each error axis HALTed alone.
- checkShippedProfileProse: a MISSING/RENAMED governed file is an error, not a
  skip — `[]` was indistinguishable from "all five validated clean".
- collectProcessSkillDirs → collectAllSkillDirs: it returns capability dirs too,
  and two catalogued steps (define-subdomains, define-bounded-contexts) need it.
- ai-development README lists process-profiles.md + step-catalogue.md (both
  copies, pinned); process-profile-gate.md ships the `$approval`-family delta
  variant too, pinned to /map-subdomains.
- brainstorm SKILL.md: one more disclosure split, budget unchanged — mirror
  28,643 → 27,979 B (29 → 693 B headroom).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 11 — a GENERATED copy is governed, and a per-skill rule is checked per skill

- `/bootstrap` Phase 0 Step 0.1 asks the profile before composing `/specify-prd`
  (disabled ⇒ exactly "not installed": HALT at Phase 0, how-to-01 pointer, never a
  prompt). Guard: the composers test now asserts the clause once per COMPOSED STEP
  ID declared in the delta, inside that step's own beat — one clause per file let
  bootstrap's two map-* beats cover a third composed step
- `checkInstalledProfileCorpus`: the installed `.pair/knowledge/**` catalogue +
  profiles are bound to the dataset (ids, how-to, requires, built-in whitelists;
  executables through the real `installedSkillDir` transform) and the manual-path
  check runs over root AGENTS.md/CLAUDE.md too. Fail-closed on a missing file
- `checkStepDelta`: each step skill's `## Process Profile` section (plus disclosed
  siblings, never a link out of the dir) must state the DIRECT and COMPOSED
  clauses — the sentence was pinned for 2 of 12, deletable in the other 10
- `sectionOfWhere` ends a section at a level-1 heading too (`###`+ stays inside):
  a key under a later `#` was a phantom "declared more than once"
- ADL extended in place (11th), mirror regenerated by `pair update`

Test-first: 16 cases RED (14 + 2) → 269 / 114 green; hub suite 5,177 → 5,200.
quality-gate exit 0; smoke-tests 20/20 PASS.

Refs: #251

* [#251] fix: review round 12 — a bound copy includes its PROSE, and a report that names a step filters it

- installed `process-profile-gate.md` bound (DIRECT/COMPOSED clauses + `auto=halt`,
  fail-closed): gutted to `TODO` it was `PASS`, exit 0, and an unattended run had no
  `auto=halt` instruction left anywhere
- worked-example sweep extracted (`profileExampleErrors`) and run over both installed
  KB copies: `spcify-prd` in the installed `custom` example was reported by nothing
- composers guard cross-checks its subject list against the `## Composed Skills` table
  and derives the composer list from the corpus — shrinking a delta reddens instead of
  de-scoping the guard
- every step report that names a catalogued step filters its `Next:` line by the
  profile; rule stated once in the convention

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [#251] fix: review round 13 — a heading is decorated on every side, and a guard's subjects come from the algorithm

- normalizeHeading strips leading decoration (non-alnum run, `N.`/`N)`) and
  collapses internal separators (`-`/`_` → space, whitespace runs). `## 🎯
  Process Profile`, `## 1. Process Profile`, `## Process  Profile`,
  `## Process-Profile` over a valid `poc` declaration each resolved to
  `default`/12 steps, zero halts — the corpus's own house style.
- composers guard: subject ids = delta ∪ `## Composed Skills` table ∪ the object
  of each `compos*` verb before `## Graceful Degradation`. Two declarations in
  one file de-scoped the guard to 147 green tests (from 149); a third edit
  gutting the beat then landed green.
- checkInstalledGateConvention binds its fourth clause (the `Next:` filter),
  mirroring the dataset-side assertion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UQJzGMhRqBRRboxMrRqFPP

* [US-251] fix: halt orphan profile keys

* [#251] chore: regenerate mirrors after rebase onto main

Regenerated with pair update (offline, local dataset) to resolve the .pair/llms.txt rebase conflict.

Refs: #251

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfhvsS5rippi6aUbbGrf6F

* [#251] fix: align ADR-025 heading with file name after rebase collision

Post-rebase file was adr-025 but title still ADR-024, causing
generateLlmsTxt to emit ADR-024 for adr-025 path and break
llms-index-conformance (build FAIL on d3ddd50). Fix heading to
ADR-025 so committed .pair/llms.txt and generator agree.

Refs: #251

* [#251] fix: bump skills-catalog Last updated to 2026-09-14 for docs:staleness

Gate docs:staleness compares header date vs newest commit touching
dataset/.skills. Header was 2026-09-13, CI reported source 2026-09-14
post-rebase. Bump to make header not older than source.

Refs: #251

* [#251] fix: restore Process Profile marker after rebase onto main post-#468

Rebase 6e37df9 lost the marker when resolving version conflict
(0.7.4 vs 0.7.0). Restore executable marker + short gate text so
checkStepMarkers passes on both dataset and mirror.

Refs: #251

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: T <t@e.com>
rucka pushed a commit that referenced this pull request Sep 14, 2026
Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466).
Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte,
reports missing/extra lines and regeneration command, wired into
ci.yml + root quality-gate. Reuses generator, never writes.

Refs: #416
rucka added a commit that referenced this pull request Sep 14, 2026
* [#416] feat: llms.txt drift gate

Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466).
Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte,
reports missing/extra lines and regeneration command, wired into
ci.yml + root quality-gate. Reuses generator, never writes.

Refs: #416

* [#416] fix: restore dev-tools package.json after squashed rebase

Merge main's yaml + format-workflow:check with 416's llms-index scripts.
Pre-push hook bypassed for squashed rebase fix.

* [#416] fix: sync pnpm-lock after squashed rebase

CI frozen-lockfile failed: 6 deps removed from apps/website/package.json
vs lock. Regenerated lock via pnpm install.

Refs: #416

* [#416] fix: restore @pair/content-ops dep for drift gate

Drift gate imports FileSystemService from @pair/content-ops.
Squashed rebase had dropped it, causing tsc Cannot find module.

Refs: #416

* [#416] fix: restore main files after squashed rebase

Squashed rebase had overwritten workflow/skill files with old versions
from fa4fc10, causing lint failures. Restore to cbf390b and keep
only 416's 22-file drift gate.

Refs: #416

* [#416] fix: sync pnpm-lock for website deps after rebase

Add 6 catalog deps that were added to apps/website/package.json
in main (6e37df9..cbf390b) but missing from squashed lock.

Refs: #416

* [#416] fix: regenerate .pair/llms.txt after rebase

Drift gate was red: 3 ADL lines missing (byte-compared artifact
decisions added by this branch but not in tracked index).
Regenerated via pnpm llms-index:regen.

Refs: #416

* [#416] fix: restore pre-push gate to main after squashed rebase

Squashed rebase had overwritten with old version, causing
format-workflow-composition lint failures. Restore to cbf390b.

Refs: #416

* [#416] fix: format dev-tools package.json

pnpm format fix for prettier:check.

Refs: #416

---------

Co-authored-by: T <t@e.com>
rucka added a commit that referenced this pull request Sep 14, 2026
* [#416] feat: llms.txt drift gate

Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466).
Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte,
reports missing/extra lines and regeneration command, wired into
ci.yml + root quality-gate. Reuses generator, never writes.

Refs: #416

* [#416] fix: restore dev-tools package.json after squashed rebase

Merge main's yaml + format-workflow:check with 416's llms-index scripts.
Pre-push hook bypassed for squashed rebase fix.

* [#416] fix: sync pnpm-lock after squashed rebase

CI frozen-lockfile failed: 6 deps removed from apps/website/package.json
vs lock. Regenerated lock via pnpm install.

Refs: #416

* [#416] fix: restore @pair/content-ops dep for drift gate

Drift gate imports FileSystemService from @pair/content-ops.
Squashed rebase had dropped it, causing tsc Cannot find module.

Refs: #416

* [#416] fix: restore main files after squashed rebase

Squashed rebase had overwritten workflow/skill files with old versions
from fa4fc10, causing lint failures. Restore to cbf390b and keep
only 416's 22-file drift gate.

Refs: #416

* [#416] fix: sync pnpm-lock for website deps after rebase

Add 6 catalog deps that were added to apps/website/package.json
in main (6e37df9..cbf390b) but missing from squashed lock.

Refs: #416

* [#416] fix: regenerate .pair/llms.txt after rebase

Drift gate was red: 3 ADL lines missing (byte-compared artifact
decisions added by this branch but not in tracked index).
Regenerated via pnpm llms-index:regen.

Refs: #416

* [#416] fix: restore pre-push gate to main after squashed rebase

Squashed rebase had overwritten with old version, causing
format-workflow-composition lint failures. Restore to cbf390b.

Refs: #416

* [#416] fix: format dev-tools package.json

pnpm format fix for prettier:check.

Refs: #416

---------

Co-authored-by: T <t@e.com>
rucka added a commit that referenced this pull request Sep 14, 2026
* [#416] feat: llms.txt drift gate (#475)

* [#416] feat: llms.txt drift gate

Squashed rebase of 17 commits onto main cbf390b (post-#468/#467/#466).
Gate compares tracked .pair/llms.txt vs generateLlmsTxt byte-for-byte,
reports missing/extra lines and regeneration command, wired into
ci.yml + root quality-gate. Reuses generator, never writes.

Refs: #416

* [#416] fix: restore dev-tools package.json after squashed rebase

Merge main's yaml + format-workflow:check with 416's llms-index scripts.
Pre-push hook bypassed for squashed rebase fix.

* [#416] fix: sync pnpm-lock after squashed rebase

CI frozen-lockfile failed: 6 deps removed from apps/website/package.json
vs lock. Regenerated lock via pnpm install.

Refs: #416

* [#416] fix: restore @pair/content-ops dep for drift gate

Drift gate imports FileSystemService from @pair/content-ops.
Squashed rebase had dropped it, causing tsc Cannot find module.

Refs: #416

* [#416] fix: restore main files after squashed rebase

Squashed rebase had overwritten workflow/skill files with old versions
from fa4fc10, causing lint failures. Restore to cbf390b and keep
only 416's 22-file drift gate.

Refs: #416

* [#416] fix: sync pnpm-lock for website deps after rebase

Add 6 catalog deps that were added to apps/website/package.json
in main (6e37df9..cbf390b) but missing from squashed lock.

Refs: #416

* [#416] fix: regenerate .pair/llms.txt after rebase

Drift gate was red: 3 ADL lines missing (byte-compared artifact
decisions added by this branch but not in tracked index).
Regenerated via pnpm llms-index:regen.

Refs: #416

* [#416] fix: restore pre-push gate to main after squashed rebase

Squashed rebase had overwritten with old version, causing
format-workflow-composition lint failures. Restore to cbf390b.

Refs: #416

* [#416] fix: format dev-tools package.json

pnpm format fix for prettier:check.

Refs: #416

---------

Co-authored-by: T <t@e.com>

* [#438] feat: opt-in business-impact.trivial-diff override

Squashed rebase onto 5a18b8d (post-#475). 14 commits -> 1.
Risk: green (trivial-diff override is opt-in, no behaviour change by default).
Intended changes: 35 files (12 from branch already on main via #413/#475).

Refs: #438

* [#438] fix: sync pnpm-lock for website deps

Refs: #438

* [#438] fix: add @pair/content-ops dep for dev-tools type-check

Squashed rebase dropped it from package.json (was in branch but not on main).
Refs: #438

* [#438] fix: sync pnpm-lock for content-ops dep

Refs: #438

* [#438] fix: restore process-step marker and skills-guide counts

Branch removed <!-- process-step: id=bootstrap --> marker (added by #475
in cc169bd) and downgraded version 0.9.0->0.8.0. Also removed workflow
skills from skills-guide. Restore to main.

Refs: #438

* [#438] fix: add llms-index scripts + regenerate .pair/llms.txt

Root package.json and dev-tools missing llms-index:check/regen scripts
(added by #475). Regenerated index to match current tree.

Refs: #438

* [#438] fix: drop stale workflow spillover, keep US-438 hunks on main files

pair-implement-batch (all 4 copies) restored to main: branch carried
#219-era full-file versions missing args.entryCapsules, breaking
engine-boundaries/engine-integration dry-runs. No US-438 commit ever
touched those files. US-438 one-liners (bootstrap trivial-diff sentence,
skills-guide Classification row) re-applied onto main versions.
turbo.json/tech-stack/way-of-working restored (post-base main additions).
Changeset file removed per no-release decision.

Refs: #438

* [#438] chore: retrigger CI

Refs: #438

* [#438] fix: ADL names workflows/agents carve-out classes like §6

Review Minor: ADL point 2 said 'skill/workflow file' but enumerated
only SKILL.md + .claude/skills/**; §6 + risk-matrix carve out
.claude/workflows/** + .claude/agents/** since round 5. Aligned.

Refs: #438

* [#438] chore: trigger mergeability recompute

Refs: #438

---------

Co-authored-by: T <t@e.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-state:ready-to-merge PR state: gates green + review approved risk:yellow Classification: medium risk tier

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant