Problem
### Blocking has no producer contract. idd-update writes it from the template - {blocker 1, or "(none)"}, the {} is model-filled, and across this repo's 55 real sections the 48 semantically-empty values use 35+ spellings (- (none), - (none — closed), - (none) — diagnosed, awaiting pickup, (無), - (none — ready for /idd-implement #107) …).
On main the emptiness of this section was read as prose by the model (idd-list Step 3.7) and judged correctly. PR #318 round 2 replaced that with a regex in idd_blocking_section — which misjudged 31 of 48 empty sections as live blockers — and at the same time promoted the signal from an idd-list display grouping to a hard abort in four skills. Round 3 of that PR stops the bleeding with a leading-token rule plus a frozen corpus-blocking.json, but the Devil's Advocate lens made the structural point: stacking character classes on an LLM-written field is the same category error round 1 made on ### Complexity, and two attempts at the regex each grew a new hole.
Source
Expected
Pick one of two shapes and record the decision in references/actionability-gate.md:
- Producer contract:
idd-update (and every writer of ### Blocking) emits a machine-checkable token — e.g. an empty section contains no bullet at all, or exactly - (none) with annotations moved to the next line — and the reader is then allowed to be strict. Needs a migration note for the 48 existing values (or a one-time normalisation pass).
- Model judgement: the shared helper returns the section's raw lines; the four consumers keep a single shared extraction but the emptiness verdict is made by the executing model against a written rubric, with the raw lines surfaced.
Either way: the choice must be validated against the 55-row corpus-blocking.json shipped by #316, and the signal-3 row of §Risk posture must state which failure direction the chosen shape accepts.
Acceptance criteria
Complexity
Plan — cross-file (helper + 4 consumers + idd-update template + reference), decision-heavy between two valid shapes, no new published API.
Problem
### Blockinghas no producer contract.idd-updatewrites it from the template- {blocker 1, or "(none)"}, the{}is model-filled, and across this repo's 55 real sections the 48 semantically-empty values use 35+ spellings (- (none),- (none — closed),- (none) — diagnosed, awaiting pickup,(無),- (none — ready for /idd-implement #107)…).On
mainthe emptiness of this section was read as prose by the model (idd-list Step 3.7) and judged correctly. PR #318 round 2 replaced that with a regex inidd_blocking_section— which misjudged 31 of 48 empty sections as live blockers — and at the same time promoted the signal from an idd-list display grouping to a hard abort in four skills. Round 3 of that PR stops the bleeding with a leading-token rule plus a frozencorpus-blocking.json, but the Devil's Advocate lens made the structural point: stacking character classes on an LLM-written field is the same category error round 1 made on### Complexity, and two attempts at the regex each grew a new hole.Source
Expected
Pick one of two shapes and record the decision in
references/actionability-gate.md:idd-update(and every writer of### Blocking) emits a machine-checkable token — e.g. an empty section contains no bullet at all, or exactly- (none)with annotations moved to the next line — and the reader is then allowed to be strict. Needs a migration note for the 48 existing values (or a one-time normalisation pass).Either way: the choice must be validated against the 55-row
corpus-blocking.jsonshipped by #316, and the signal-3 row of §Risk posture must state which failure direction the chosen shape accepts.Acceptance criteria
references/actionability-gate.mdwith the rejected alternative and whycorpus-blocking.json0 FP / 0 FN under the chosen shapeComplexity
Plan — cross-file (helper + 4 consumers + idd-update template + reference), decision-heavy between two valid shapes, no new published API.