|
| 1 | +# Proposal-path enumeration goes stale when proposal commits to main first — anchor to scope invariant |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Diff-enumerated ACs that name the proposal file as one of the expected paths |
| 6 | +in `git diff --name-only main...HEAD` are structurally fragile in the |
| 7 | +proposal-elaboration → work two-phase workflow. When the proposal commit lands |
| 8 | +on `main` *before* the implementation slot forks (the common case for |
| 9 | +medium/large tasks), `main...HEAD` returns only the implementation paths — |
| 10 | +the proposal is no longer ahead of `main`. The literal four-path enumeration |
| 11 | +silently fails through no fault of the coder. |
| 12 | + |
| 13 | +`task-9cd6cdb9` (PR #490, `orchestration-patterns lockstep + stash-prod`) hit |
| 14 | +this in round 1. The reviewer correctly flagged via REQUEST_CHANGES; the |
| 15 | +coder reconciled by editing the proposal in the same PR (commit `a2dd03b`: |
| 16 | +clarifier + awk-syntax fix + AC12 Recovery clause), which put the proposal |
| 17 | +path back into `main...HEAD`. The proposal author had even pre-written an |
| 18 | +in-line Recovery clause anticipating the failure mode — but the structural |
| 19 | +fix (normalising the recovery into the reference doc so future proposals |
| 20 | +don't keep re-authoring the same fragile literal-four-path enumeration) was |
| 21 | +never landed. |
| 22 | + |
| 23 | +This proposal lands the structural fix at the **reference-doc layer**, where |
| 24 | +the user's standing pattern (`feedback_reference_layer_not_inline.md`) places |
| 25 | +contract-heavy AC guidance. The worker prompt already hooks into the |
| 26 | +reference doc ("when the task's ACs are unusually contract-heavy, consult |
| 27 | +`docs/ac-rigor-reference.md`"); we add a sibling `### ` clause to the |
| 28 | +Verification-evidence family that future draft-proposal-worker invocations |
| 29 | +will pick up via that hook. |
| 30 | + |
| 31 | +Linked: task-9cd6cdb9 retrospective; PR #490; auto-memory |
| 32 | +`feedback_proposal_in_diff_ac_stale_when_proposal_on_main.md`. |
| 33 | + |
| 34 | +## Acceptance Criteria |
| 35 | + |
| 36 | +- [ ] AC1 — A new `### ` clause is appended to |
| 37 | + `docs/ac-rigor-reference.md` under `## Verification-evidence family`, |
| 38 | + titled exactly `### Proposal-path enumeration goes stale when proposal |
| 39 | + commits to main first — anchor to scope invariant`, as a sibling of |
| 40 | + the existing `### Diff-enumerated verification lines go stale — |
| 41 | + anchor to invariants, not snapshots`. Falsifier: `awk |
| 42 | + '/^## Verification-evidence family/,/^## /' docs/ac-rigor-reference.md |
| 43 | + | grep -F "### Proposal-path enumeration goes stale when proposal |
| 44 | + commits to main first"` returns one line; the same `awk` slice also |
| 45 | + contains `### Diff-enumerated verification lines go stale`. |
| 46 | +- [ ] AC2 — The new clause body names the failure mode in literal terms: |
| 47 | + the proposal commit lands on `main` *before* the implementation |
| 48 | + branch forks, so `git diff --name-only main...HEAD` returns only the |
| 49 | + implementation paths and a literal four-path enumeration of paths |
| 50 | + including the proposal file silently misses one. Falsifier (within |
| 51 | + the new clause's text range): `grep -F "before the implementation"` |
| 52 | + OR `grep -F "before the implementation branch"` returns a hit. |
| 53 | +- [ ] AC3 — The new clause prescribes the (b)-form load-bearing invariant |
| 54 | + as the durable AC shape: an *implementation-path scope invariant* |
| 55 | + ("no `src/**`, `scripts/**`, `templates/**`, or `*.test.ts` paths |
| 56 | + appear in `git diff --name-only main...HEAD`"-style enumeration of |
| 57 | + what must NOT be in the diff) rather than a literal enumeration of |
| 58 | + paths that must be in the diff. The clause explicitly contrasts the |
| 59 | + two shapes — "what's NOT in the diff" survives a merge-base advance; |
| 60 | + "exactly these paths are in the diff" doesn't. Falsifier: the new |
| 61 | + clause contains the literal phrase `scope invariant` AND at least |
| 62 | + one of `no src/`, `no source/`, or `no `\``src/**`\` (one is sufficient). |
| 63 | +- [ ] AC4 — The new clause cites `task-9cd6cdb9` and `PR #490` (or |
| 64 | + `pull/490`) as the precipitating instance, in the same clause body |
| 65 | + (one sentence is sufficient). Falsifier: `grep -F "task-9cd6cdb9" |
| 66 | + docs/ac-rigor-reference.md` AND (`grep -F "PR #490" |
| 67 | + docs/ac-rigor-reference.md` OR `grep -F "pull/490" |
| 68 | + docs/ac-rigor-reference.md`) both return ≥1 hit, and both hits land |
| 69 | + between the new clause's `### ` heading and the next `### ` or `## ` |
| 70 | + heading. |
| 71 | +- [ ] AC5 — The new clause cross-links the sibling `### Diff-enumerated |
| 72 | + verification lines go stale — anchor to invariants, not snapshots` |
| 73 | + clause, in the same toolset / distinct trigger style modelled on the |
| 74 | + stash-prod ↔ stash-and-rerun cross-link (clause body of `Stash-prod |
| 75 | + mutation test` already cites `No-regression framing when the gate |
| 76 | + baseline is red` reciprocally). The cross-link names the distinction |
| 77 | + explicitly: same toolset (`git diff --name-only main...HEAD`), |
| 78 | + distinct trigger (within-branch growth vs cross-branch merge-base |
| 79 | + advance). Falsifier (within the new clause's text range): `grep -F |
| 80 | + "Diff-enumerated"` returns a hit AND one of `same toolset` / |
| 81 | + `distinct trigger` / `merge-base` appears in the same paragraph. |
| 82 | +- [ ] AC6 — The new clause prescribes the recovery pattern: a same-PR |
| 83 | + proposal edit (any substantive change — a clarifier, a recovery |
| 84 | + clause, an awk-syntax fix) puts the proposal path back into |
| 85 | + `main...HEAD` and reconciles the literal enumeration with the |
| 86 | + invariant, so a coder who hits the failure mode mid-round has a |
| 87 | + mechanical out without re-opening the proposal phase. Falsifier |
| 88 | + (within the new clause's text range): `grep -E "same[ -]PR" |
| 89 | + docs/ac-rigor-reference.md` returns ≥1 hit. |
| 90 | +- [ ] AC7 — `skills/worker-conventions.md`'s Verification-evidence family |
| 91 | + pointer (currently the third bullet under `## AC verification rigor`, |
| 92 | + grouped as "Process-around-the-AC") is updated to list the new |
| 93 | + clause's title alongside the existing `Diff-enumerated verification |
| 94 | + lines go stale — anchor to invariants, not snapshots` clause. |
| 95 | + Falsifier: `grep -F "Proposal-path enumeration goes stale when |
| 96 | + proposal commits to main first" skills/worker-conventions.md` |
| 97 | + returns ≥1 hit. |
| 98 | +- [ ] AC8 — The clause-count line (currently |
| 99 | + `docs/ac-rigor-reference.md:5` — "sixteen clauses across five |
| 100 | + thematic families") is updated from `sixteen` to `seventeen`. |
| 101 | + Falsifier: `grep -F "sixteen clauses" docs/ac-rigor-reference.md` |
| 102 | + returns 0 hits AND `grep -F "seventeen clauses" |
| 103 | + docs/ac-rigor-reference.md` returns ≥1 hit. |
| 104 | +- [ ] AC9 — Negative control on worker prompt: `skills/ludics-draft- |
| 105 | + proposal-worker.md` is NOT modified. The worker prompt's existing |
| 106 | + "consult `docs/ac-rigor-reference.md` when ACs are contract-heavy" |
| 107 | + hook stays the entry point; AC-shape guidance lives at the reference |
| 108 | + layer per `feedback_reference_layer_not_inline.md`. Falsifier (a |
| 109 | + breach of the negative control): `git diff --name-only main...HEAD` |
| 110 | + includes `skills/ludics-draft-proposal-worker.md`. |
| 111 | +- [ ] AC10 — Doc-only PR scope invariant (the (b)-form this proposal is |
| 112 | + itself prescribing — eats its own dog food): no `src/**`, no |
| 113 | + `scripts/**`, no `templates/**`, no `*.test.ts`, and no |
| 114 | + `docs/proposals/**` (other than this proposal file) path appears in |
| 115 | + `git diff --name-only main...HEAD`. Falsifier (a breach of the |
| 116 | + invariant): `git diff --name-only main...HEAD | grep -E |
| 117 | + '^(src/|scripts/|templates/|.*\.test\.ts$)'` returns ≥1 hit. |
| 118 | + |
| 119 | +## Context |
| 120 | + |
| 121 | +### Touch sites (verified) |
| 122 | + |
| 123 | +- `docs/ac-rigor-reference.md` — append a new `### ` clause inside |
| 124 | + `## Verification-evidence family`, as a sibling of `### Diff-enumerated |
| 125 | + verification lines go stale — anchor to invariants, not snapshots` |
| 126 | + (currently around line 85). The clause-count line (currently line 5) |
| 127 | + also updates from `sixteen` to `seventeen`. |
| 128 | +- `skills/worker-conventions.md` — extend the Verification-evidence-family |
| 129 | + pointer (third bullet under `## AC verification rigor`, currently |
| 130 | + grouped as "Process-around-the-AC") to list the new clause's title |
| 131 | + alongside the existing diff-enumerated clause. One-line edit. |
| 132 | + |
| 133 | +### Touch site that is NOT modified (negative control) |
| 134 | + |
| 135 | +- `skills/ludics-draft-proposal-worker.md` — explicitly out of scope. |
| 136 | + The worker prompt deliberately doesn't carry AC-shape templates; its |
| 137 | + "consult `docs/ac-rigor-reference.md`" hook (currently around line 105) |
| 138 | + is the entry point, and modifying the prompt to inline scope-AC |
| 139 | + guidance would contradict the user's standing reference-layer pattern |
| 140 | + (`feedback_reference_layer_not_inline.md`). |
| 141 | + |
| 142 | +### Style precedent for the cross-link |
| 143 | + |
| 144 | +The `### Stash-prod mutation test` clause models the pattern: it cites |
| 145 | +`No-regression framing when the gate baseline is red` reciprocally with |
| 146 | +"Same toolset … but a distinct probe: stash-and-rerun answers …, while |
| 147 | +stash-prod answers …" — and notes "a reader landing on either clause |
| 148 | +should follow the cross-link to find the other." The new clause uses |
| 149 | +the same shape: same toolset (`git diff --name-only main...HEAD`), |
| 150 | +distinct trigger (within-branch growth covered by the existing diff- |
| 151 | +enumerated clause; cross-branch merge-base advance covered by the new |
| 152 | +one). |
| 153 | + |
| 154 | +### Why the (b)-form invariant, not the literal enumeration |
| 155 | + |
| 156 | +The original task's Tentative Design (lines 81–157) framed the choice as |
| 157 | +"three options ranked by leverage" and concluded that the |
| 158 | +reference-doc clause is the right primary fix. The (b)-form invariant |
| 159 | +("no source/test/schema paths in diff") is enumeration-tolerant: it |
| 160 | +holds whether the proposal commit landed on `main` first or not, because |
| 161 | +it's expressed in terms of what must *not* appear in the diff rather |
| 162 | +than what must. AC10 of this proposal eats its own dog food by stating |
| 163 | +its scope invariant in exactly that shape. |
| 164 | + |
| 165 | +### Cross-references already resolved |
| 166 | + |
| 167 | +- Auto-memory `feedback_proposal_in_diff_ac_stale_when_proposal_on_main.md` |
| 168 | + in the coder's project memory captures the recovery from the working |
| 169 | + side; this proposal promotes the essence of that auto-memory to the |
| 170 | + reference doc so future *proposal authoring* avoids the latent bug. |
| 171 | +- `feedback_reference_layer_not_inline.md` — the user's standing pattern |
| 172 | + for AC-shape guidance: reference doc, not skill template body. |
| 173 | +- `feedback_competent_swe_filter.md` — the new clause is a structural |
| 174 | + workflow fix (recurring failure mode in the two-phase workflow), not |
| 175 | + a hygiene-flavoured suggestion; the filter passes. |
| 176 | + |
| 177 | +## Approach |
| 178 | + |
| 179 | +*Suggested approach — agents may deviate if they find a better path.* |
| 180 | + |
| 181 | +1. Append the new `### ` clause to `docs/ac-rigor-reference.md` inside |
| 182 | + `## Verification-evidence family`, immediately after the existing |
| 183 | + `### Diff-enumerated verification lines go stale — anchor to |
| 184 | + invariants, not snapshots` clause (one paragraph, prose-only, in the |
| 185 | + same dense-prose voice as the surrounding clauses). Hit AC2, AC3, |
| 186 | + AC4, AC5, AC6 in the body; satisfy AC1's structural placement. |
| 187 | +2. Update line 5's "sixteen clauses" to "seventeen clauses" (AC8). The |
| 188 | + "five thematic families" count is unchanged — the new clause is a |
| 189 | + sibling within the existing Verification-evidence family. |
| 190 | +3. Edit `skills/worker-conventions.md`'s Verification-evidence-family |
| 191 | + pointer to list the new clause title (AC7). One-line addition, same |
| 192 | + semicolon-separated style as the existing list of clauses in that |
| 193 | + bullet. |
| 194 | +4. Verify AC9 (worker prompt unchanged) and AC10 (no `src/**` / |
| 195 | + `scripts/**` / `templates/**` / `*.test.ts` paths in the diff) by |
| 196 | + running the falsifier greps locally before committing. |
| 197 | +5. The reciprocal cross-link from the existing `### Diff-enumerated |
| 198 | + verification lines go stale` clause to the new one is *optional* |
| 199 | + under this proposal's ACs — desirable for symmetry with the |
| 200 | + stash-prod ↔ stash-and-rerun precedent, but the absorb-vs-follow-up |
| 201 | + judgement (per `worker-conventions.md` § Scope) belongs to the |
| 202 | + coder. If absorbed, it's a one-sentence addition to that clause. |
| 203 | + |
| 204 | +## Scope |
| 205 | + |
| 206 | +**In scope.** |
| 207 | + |
| 208 | +- `docs/ac-rigor-reference.md`: new `### ` clause + clause-count update. |
| 209 | +- `skills/worker-conventions.md`: one-line pointer addition. |
| 210 | + |
| 211 | +**Out of scope.** |
| 212 | + |
| 213 | +- `skills/ludics-draft-proposal-worker.md` — explicit negative control |
| 214 | + (AC9). The worker prompt is not modified. |
| 215 | +- Any code changes (`src/**`, `scripts/**`, `templates/**`, `*.test.ts`) |
| 216 | + — explicit negative control (AC10). Doc-only PR. |
| 217 | +- Any other clause additions, taxonomy reshuffling, or family |
| 218 | + reorganisation in `docs/ac-rigor-reference.md`. The new clause is |
| 219 | + additive and lives inside the existing Verification-evidence family. |
| 220 | +- General revision of all `main...HEAD`-based ACs across past proposals. |
| 221 | + Out of scope per the task's Notes section ("Scope of 'diff-enumerated |
| 222 | + ACs'"). |
| 223 | + |
| 224 | +**Dependencies.** None. `task-9cd6cdb9` is `relates_to`, not blocking; |
| 225 | +PR #490 has already merged. |
0 commit comments