[FEAT] choice-first decision rendering doctrine (#190) - #191
Merged
Merged
Conversation
spectra-propose artifacts for #190: a cross-skill doctrine that IDD skills SHALL render enumerable decisions as AskUserQuestion choices (recommended option first) rather than asking the human to articulate in free-text; free-text is a named-exception fallback only when the option space is genuinely open. Design aligned via spectra-discuss (attended, 2026-06-19): - Decision 1: cross-skill doctrine (MANIFESTO + new spec capability) - Decision 2: SHALL + named fallback - Decision 3: extract shared; idd-diagnose Layer V D.1 references it Proposal only — implementation (MANIFESTO + idd-diagnose SKILL.md patches) deferred to spectra-apply pending review. Refs #190
Implement the spectra-apply step for #190: - MANIFESTO.md: new "Choice-first decision rendering(人挑,不要人寫)" sub-section under the NSQL Confirmation Protocol section — enumerable decision points SHALL render AskUserQuestion choices; free-text is a named-exception fallback only when the option space is genuinely open. - idd-diagnose SKILL.md Step 3.4 Layer V D.1: refactored to reference the doctrine as the single source of truth (vagueness-clarification instance) instead of re-specifying the choice-vs-free-text rule. - idd-diagnose SKILL.md Step 4 Stage 1: new normative note applying the doctrine to stakeholder-decision surfacing (the #190 incident gap). - tasks.md: implementation + validation checklist marked complete. openspec validate: pass. Refs #190
…verify P1) Adversarial review (idd-verify) found the doctrine's unattended clause said "auto-apply the recommended option, mirroring Layer V" — but Layer V's actual unattended behavior (SKILL.md section F) applies `proceed anyway`, which is NOT the recommended option when max_score >= 5 (recommended is clarify/escalate, both human-requiring). The doctrine was unfaithful to the very instance it cites as single source of truth. Reworded the unattended clause in all 4 places (MANIFESTO, spec scenario 4, idd-diagnose Step 4 note, proposal/design) to: "apply a safe non-blocking default per the skill's existing unattended convention (NOT necessarily the recommended option); e.g. Layer V's proceed-default". Also clarified that unattended is signalled via the UNATTENDED MODE directive, not a literal INTERACTION=unattended env toggle (P2). tasks.md updated. Refs #190
kiki830621
added a commit
that referenced
this pull request
Jun 19, 2026
spectra-archive (openspec archive): promote the choice-first-decision-rendering spec delta to openspec/specs/choice-first-decision-rendering/spec.md and move the completed change to openspec/changes/archive/2026-06-19-add-choice-first-decision-doctrine/. Mechanical housekeeping after PR #191 merged the doctrine implementation. No behavior change — the doctrine prose (MANIFESTO + idd-diagnose) already landed in #191. Refs #190
kiki830621
added a commit
that referenced
this pull request
Aug 31, 2026
**invisible_line 的貪婪 regex(純引用 → compliant)** `^[ \t]*<!--.*-->[ \t]*$` 的 `.*` 是貪婪的:在 `<!-- a --> <blockquote><!-- b -->` 上它從第一個 `<!--` 跑到最後一個 `-->`, 把中間的可見元素一起吞掉。引用的開啟標籤因此變成隱形,heading 成為 lead line,一段純引用被判 `compliant` —— 那是唯一「不印在任何 section」的分類, 所以該 issue 同時對稽核靜默、也被 `--retroactive` 拒絕。 非貪婪救不了,這點值得寫下來因為它是所有人第一個會試的:`<!--.*?-->[ \t]*$` 一樣會 match,因為 `$` 會逼著懶惰量詞繼續延伸到尾端是空白為止。改用 tempered dot `(?:(?!-->).)*` 讓每個註解停在自己的終止符,`+` 再要求該行其餘 部分只能是另一個註解或空白。lookahead 對本機 Oniguruma 實測過、不是假設。 fixture #190(重現)/#191(邊界:不以 `-->` 結尾,貪婪版也沒 match,保留因為 那是日後「簡化」會落地的地方)/#192(控制組:真的只有註解的行仍須跳過, 否則修法等於把功能關掉換綠燈)。編號用 190-192 而非 187-189:第一版跟既有的 `#187 autolink then hash` 撞號,兩條 refutation 都對著**那一張**通過,我自己 新增的那張根本沒被檢查。 **unsafe_filename 的 null(verify 永久失敗)** refuse 記成 `{filename: null}`,`jq -r '.files[].filename'` 印出字面 `null`、 `[ -z ]` 為假,於是去測 `-f "$ATTACH_DIR/null"`、記一筆 missing、exit 1 —— 而這是 idd-close Step 1.4 的 gate。與它形狀相同的 `download_failed` 差在: 後者是**暫時**的,重抓就清掉,正是這個 gate 該逼人做的事;refuse 是**確定 性**的,重抓重現同一個 refuse。沒有補救路徑的 gate 不是 gate,是把 issue 砌死。 - verify:`select(.filename != null)`,refuse 改為大聲揭露但不擋;真正的 drift 照擋(f14e 控制組守住這件事)。 - check:refuse 的 URL 本來就在 KNOWN 裡,所以它印一句 bare「up-to-date」蓋過 一個不在磁碟上、也永遠不會在的附件。改成照常報 up-to-date 但另外列出 refuse。 兩個 consumer 原本朝相反方向壞:一個永久硬擋、一個靜默放行。 **測試環境的既有缺口**:這個 suite 從來沒有 stub `curl`,所以每個 fixture 的 「下載」其實都打了真網路並失敗、記成 download_failed —— 也就是說沒有任何斷言 分得出成功與失敗的下載,f13c 是在一個檔案從未存在的條目上通過的。補上 curl stub,f13c 加驗 `.error == null` 與檔案真的落地。 **兩條自己寫的空洞斷言,mutation 抓到後才修**: f14a 用 `bash -c 'run_pa ...'`,而 `run_pa` 是 shell function —— 子 shell 裡 沒有它,指令失敗、管線無輸出、否定 grep 因此通過;改成先導到檔案再斷言。 f14c/f14d 的 needle 是裸字 `refused`,而摘要行與逐 URL 行都含這個字,刪掉任一 行另一行都能滿足它;改成各自唯一的字串,並補「有沒有指出是哪個 URL」。 150 + 48 條,56 個 suite 全綠;每條新斷言都以 mutation 驗過重量。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #190
Summary
跨 skill Choice-First Decision Rendering doctrine:決策 / 澄清點選項可列舉時,
idd-*skills SHALL 用AskUserQuestionrender 候選(含推薦項),而非請 user 自由文字 articulate;free-text 是具名例外 fallback(只在選項空間真的開放、AI 無法列舉時,且須寫明為何無法列舉)。choice-first-decision-rendering(1 requirement / 6 scenarios,含 unattended、scope 排除純資訊輸出、D.1-as-instance)Design 經 spectra-discuss(attended) 對齊 3 決策:cross-skill doctrine / SHALL + named-fallback / D.1 references it。
Verification
openspec validate:PASSproceed anyway(max_score 5/6 時推薦項是需要人的 clarify/escalate)→ 已修(c93c0c8,4 處措辭改為「安全 non-blocking 預設」)+ re-validate PASS。faithfulness(3 decisions)/ Non-Goals / spec-format 全 PASS。openspec validate+ 獨立 adversarial doctrine review 替代。Checklist
/idd-close #190(manual gate + closing summary;無 auto-close trailer)Related / Non-Goals
idd-clarify(不同軸:術語審計 vs 決策渲染);與 in-flightadd-idd-clarify-skill(9/9 done)無碰撞🤖 Generated by /idd-all (attended). Do NOT add a close trailer (Closes/Fixes/Resolves) — IDD discipline requires manual
/idd-closeafter merge.