Repository navigation
fix: spectra-archive-post-ic linked-issue escape hatch + prose detection (#170) - #171
Conversation
…ion (#170) The --linked-issue override validated membership against the detected candidate set even when that set was EMPTY, so when detection found nothing the explicit override was rejected too — both failure modes fired together exactly when the fallback was needed (#167's IC had to be posted manually). Now the membership check applies only when candidates were actually detected; an empty set treats --linked-issue as the authoritative escape hatch. Integer validation reordered first (emit_outcome exits). Also widen detection fallback 2 to match the IDD-prose form "issue #N" (what /spectra-propose writes in tasks.md), not just Refs/Closes/Fixes. Tests: +2 fixtures (12 prose-issue detection, 13 empty-candidate override); 11 existing still pass (fixture 09 stays rejected on its non-empty set). Refs #170
Verify Report — PR #171 (#170)Engine5 general-purpose Agents (Requirements / Logic / Security / Regression / Devil's Advocate) + Codex (gpt-5.5, xhigh). Test suite re-run independently by 3 reviewers + Codex: 13/13 PASS. AggregatePASS — 0 hard-blocking. The core #170 fix (empty-set escape hatch + integer-first reorder) is confirmed correct by all 6: Findings (merged across 6 sources)
Scope CheckClean — diff touches only PlanPer same-PR-fix discipline: fixing #1 (word-boundary), #2 (reject 0), #4 (doc), #6 (count) in this PR + re-running the suite. #3 (the deeper membership-semantics conflation + wrong-existing mis-post) → follow-up issue. #5 accepted as by-design. |
- Word-boundary anchor the fallback-2 regex `(^|[^[:alnum:]_])` so `[Ii]ssue` no longer substring-matches `reissue`/`tissue` (verify P2, 6/6 consensus). Codex's escalation: a spurious candidate flips the path off the escape hatch. - Reject 0 in the --linked-issue integer check (`^[1-9][0-9]*$`) — matches the "positive integer" message; `0` would otherwise post to /issues/0 (codex P3). - Document fixture 13's /tmp-cwd coupling: escape-hatch reachability is detection-emptiness-dependent; production posts the IC pre-commit so F3 git-log sees an untracked archive path → empty (DA-3 / codex). - SKILL.md fixture count 11 -> 14 in both mirrors (this PR added 3 fixtures). Tests 13 -> 14 (word-boundary fixture). All GREEN. The deeper membership- semantics design (spurious candidate defeats override; wrong-but-existing silent mis-post) is tracked in #172. Refs #170
Verify findings resolved (commit
|
| # | Sev | Fix |
|---|---|---|
| 1 | P2 | Word-boundary anchor (^|[^[:alnum:]_]) on the fallback-2 regex — reissue #5/tissue #9 no longer false-match. + fixture 14 asserting it. |
| 2 | P3 | --linked-issue integer check tightened to ^[1-9][0-9]*$ — rejects 0 (was posting to /issues/0 despite the "positive integer" message). |
| 4 | LOW | fixture 13 README.md documents the /tmp-cwd coupling (escape-hatch reachability is detection-emptiness-dependent; production posts IC pre-commit → F3 sees an untracked archive → empty). |
| 6 | trivial | SKILL.md fixture count 11 → 14 (both mirrors). |
| 3 | MEDIUM | Follow-up #172 — the deeper membership-semantics design (spurious candidate defeats override; wrong-but-existing silent mis-post). Beyond #170's reported scope. |
| 5 | P3 | emit_outcome exit-0-on-failure — accepted as by-design (best-effort IC post per #56; archive itself already succeeded). |
Tests: 13 → 14, all GREEN. bash -n clean. The core #170 double-failure (empty-set escape hatch + integer-first reorder) was confirmed correct by all 6 reviewers and is unchanged.
Phase: verified (no remaining blocking or in-PR findings; #172 tracks the design follow-up).
**1. #317 的偵測器:檔案層級的 deference 是一張赦免令。** `docs/workflows.md:570` 寫著「Plan tier EnterPlanMode 需 user approve,unsupervised loop 無人 approve,**卡住**」—— 正是我在**同一個檔案 163 行之前**剛修掉的那句話, 原樣復活。 **偵測器找到了它,然後丟掉。** 因為 deference 是**檔案層級**檢查:我在 407 行加 的那個「見 dispatch table」指標,讓**整份文件**的其他複述都被豁免。**我的修法自己 造出了藏住違反的赦免。** 改成 per-claim:deference 必須落在該宣稱附近(±10 行,比 claim 的 ±5/同列寬, 因為表格的 caption 合理地涵蓋它的列),不是檔案裡任何一處。 這條在 acid 下**第一次沒有重量** —— 還原成檔案層級仍然全綠,因為被藏住的那個 違反在同一個 commit 裡也被修掉了。**這正是這一輪一直在生產的形狀:守衛的對象被 移除了,於是沒有東西證明守衛有效。** 補一個專門的控制組(植入一個「一處 defer、 遠處複述」的檔案),還原成檔案層級才會紅。 **2. 我把不是 heading 的東西釘成了「summary 在那裡」。** `<!-- x --> ## Closing Summary` 與 `<a name="cs"></a>## Closing Summary` **不是 CommonMark heading** —— ATX heading 必須是該行的開頭,前面有 inline HTML 就是段落。**用 markdown-it 實測,不是推論。** 上一輪我把 `html_pfx` 加進**嚴格**的 `lead_re` 去接受它們,然後寫測試把那個行為 釘住 —— 一個非 heading 被宣告成 `casing`(正面斷言)。**放寬嚴格那一半正是 round 5 的壞法,而我在寫下那句話的下一輪又做了一次。** `lead_re` 拿掉 html_pfx。`present_re` / `html_re` 保留 —— 在那裡過度偵測只是不 採取破壞性動作。fixture #170/#171 的斷言反過來:兩者現在是 advisory(`present`), 且明確斷言**不得**進 CASING。 acid:`html_pfx` 放回 lead_re → 紅 4;deference 還原成檔案層級 → 紅 1。 全 suite 52/52,classifier 142 assertions。
round-10 的 backstop 幾乎抓得到形狀辨識器抓得到的一切,所以它**遮住**了它們。
實測:清空 `html_pfx`(round-9 整條 inline-tag 白名單)在 `mentioned` 拆出來之前
全綠;把四個辨識器換成 `false` 只紅兩條。round 9 那 45 行「哪些 tag 可以算不可見
前綴」的推理,沒有任何東西守著。
拆出 `mentioned` 之後恢復了大部分重量(四辨識器全殺 → 21 紅),但 `html_pfx`
自己仍只動得了兩條。所以 stage 1 單獨跑一次:把出貨的 script **複製**一份、關掉
backstop 分支、對同一批 fixture 跑。不在production script 加測試專用開關 —— 一個
會改變安全分類器判定的環境變數,遲早會被不是在測試的人碰到。
**而這一跑翻出了本輪最尖銳的一個事實**:round 9 加的七個「讀者看得見、辨識器看
不見」fixture,有**五個**根本不被 round 9 自己的 regex 認得。
#170 #171 #172 present 辨識器真的看得到
#173 #183 #184 unrecognised stage 1 完全看不到,
#185 #186 unrecognised 唯一的覆蓋來自 round-10 的 backstop
也就是說那五條 `is NOT in MISSING` 斷言,一直是靠**晚一輪才寫的機制**通過的。
fixture 測的是**結果**,斷言的文字暗示的是**機制**,中間沒有東西把兩者接起來。
原因是結構性的,所以記錄而不是補洞:#184 的 tag 屬性跨行,而掃描是逐行的,任何
單行 regex 都不可能匹配;#183 的 `<b>` 不在 `html_re`(h1-h6 + summary),而
`emph_re` 管的是 markdown 強調不是 HTML 粗體;#173 的 `<details>` 與 #186 的
`<blockquote>` 不在 `html_pfx` 白名單裡 —— **而且應該不在**:它們會 render 出可見
元素,round 9 自己的判準就是只有不可見前綴才能跳過。為了換一條綠線把它們加進
白名單,會破壞那條白名單存在的意義。
把辨識器加寬到涵蓋它們,就是 round 10 已經取代掉的那條列舉跑步機。缺的不是覆蓋
範圍,是「哪一層負責什麼」的誠實陳述 —— 所以斷言就寫成那個:`s1_seen` 與
`s1_backstop_only` 兩組,後者在某天真的被 stage 1 認出來時會轉紅並要求更新註記。
三個 mutation 各自轉紅:html_pfx 清空(2)/ 放寬成任意 tag、即 round-5 回歸(5)/
拿掉 html_re(3)。56 個 suite 全綠。
Refs #170
Summary
Fixes the
spectra-archive-post-ic.shdouble-failure surfaced when archiving #167: detection missed the prose-onlyissue #Nreference AND--linked-issuerejected on an empty candidate set — so both the auto-detector and its manual override failed together exactly when the fallback was needed (#167's Implementation Complete had to be posted by hand).--linked-issuemembership validation now only runs when detection found candidates (the disambiguation case); an empty set treats the explicit override as authoritative.issue #Nform that/spectra-proposewrites, not justRefs/Closes/Fixestrailers.Checklist
Test plan
bash .claude/scripts/tests/spectra-archive-post-ic/test.sh→ 13/13 PASS (2 new fixtures + 11 existing).