@pilotspace/add 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,9 +31,15 @@ Before the build, the task pre-declares its **build expectations** — the obser
31
31
  - [ ] Coverage did not decrease.
32
32
  - [ ] No test or contract was altered during the build.
33
33
  - [ ] Every pre-declared build expectation is confirmed by real evidence (not merely a green test).
34
+ - [ ] Every §1 Must/Reject rule still traces to a §2 scenario tag or a §4 `covers:` line.
35
+ - [ ] Every symbol §3's contract cites still resolves in the *current* tree, not just at Ground SHA.
34
36
 
35
37
  If any of these is false, stop here and return to the build; there is nothing to verify yet.
36
38
 
39
+ A green suite proves the tests you wrote pass — it says nothing about a rule you never wired a scenario or test to at all. That is a different failure than the ones Part four covers: not a cheated pass, but a rule with no trace of ever being checked. `add.py check` scans every task project-wide for exactly this — a §1 Must or Reject with no §2 scenario tag and no §4 `covers:` line — but that sweep is easy to forget to run. `add.py audit`'s `rule_coverage_gap` notice surfaces the SAME check for the task actually at this gate, the moment it reaches Verify (a task that never adopted the tag convention at all is silently grandfathered, never retro-flagged). Neither blocks the gate; both make an already-real gap impossible to miss.
40
+
41
+ The second check guards against a quieter kind of drift. §0's Ground SHA anchors the symbols §3's contract cites to the commit they were read at — but code moves *during* the build that follows. Before this gate, re-resolve every one of those symbols against the tree as it stands now, not the Ground SHA snapshot, and record it in §6's **Live-verify evidence** block. A moved or renamed anchor caught here is a one-line note; the same drift left silent is a future reader chasing a line number that no longer means what it did at Ground.
42
+
37
43
  ## Part two — check what tests miss
38
44
 
39
45
  Automated tests are excellent at behavior on defined inputs and poor at a few specific things. Check those by hand, every time:
@@ -77,6 +83,7 @@ A security finding is always a `HARD-STOP`; it is never waved through with a wai
77
83
 
78
84
  - [ ] All tests pass (the evidence).
79
85
  - [ ] Every pre-declared build expectation is confirmed by observable evidence.
86
+ - [ ] Every §1 rule traces to §2/§4; every §3-cited symbol still resolves in the current tree.
80
87
  - [ ] Concurrency/timing of the risky operation is safe.
81
88
  - [ ] No exposed secrets, injection openings, or unexpected dependencies.
82
89
  - [ ] Layering and dependencies follow `CONVENTIONS.md`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilotspace/add",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
5
5
  "bin": {
6
6
  "add": "bin/cli.js"
@@ -18,6 +18,7 @@
18
18
  "files": [
19
19
  "bin/",
20
20
  "skill/",
21
+ "agents/",
21
22
  "tooling/add.py",
22
23
  "tooling/add_engine/",
23
24
  "!tooling/add_engine/__pycache__",
@@ -120,8 +120,9 @@ once the human confirms, rewrites `SOUL.md` (the human is the only writer) — `
120
120
 
121
121
  - **§3 CONTRACT FROZEN** → build→verify is a dynamic, auto-gated run (`autonomy: auto` default; lower to
122
122
  `conservative`/`manual` for a human gate) — `run.md`. Pipeline ready tasks behind frozen
123
- contracts — `streams.md`. Delegate one piece of your plan to a subagent (when to spawn, the prompt
124
- template, the tier) `advisor.md`. Self-score a draft (0–1 across six dimensions, refine if any < 0.9)
123
+ contracts — `streams.md`. Delegate one piece of your plan to a subagent prefer the named roster
124
+ (`add-design`/`add-build`/`add-verify`/`add-persona`/`add-advisor`) over an ad-hoc spawn; when to
125
+ spawn, the prompt template, the tier — `advisor.md`. Self-score a draft (0–1 across six dimensions, refine if any < 0.9)
125
126
  — `confidence.md`. Both advisory; the engine never spawns.
126
127
  - **Small, low-risk task**, less ceremony → the **fast lane**: `new-task --fast` scaffolds the minimal
127
128
  `TASK.fast.md`, bundle approved in one freeze — `phases/fast-lane.md`. Floor held (frozen contract ·
@@ -11,6 +11,8 @@ Spawn when the piece is **separable and worth the round-trip**: a broad sweep; a
11
11
 
12
12
  Do **not** spawn for narrow, cheap work — pay the round-trip only when the piece is big or independent enough. When in doubt, do it in-context.
13
13
 
14
+ **Prefer the named roster.** Check first whether the piece fits one of ADD's five phase specialists — `add-design` (setup–contract) · `add-build` (tests·build) · `add-verify` (verify·observe) · `add-persona` (fit-persona selection) · `add-advisor` (a consultative second opinion) — before an ad-hoc spawn; each already carries the worker contract below.
15
+
14
16
  ## The 3-lens sequential checklist at verify
15
17
 
16
18
  At Verify, sweep security → concurrency → architecture in order. **Security HARD-STOP ends the checklist** (leave the rest blank). Each lens returns: **CLEAR** · **HARD-STOP** (security only) · **RESIDUE** (concurrency/architecture).
package/skill/add/loop.md CHANGED
@@ -50,8 +50,8 @@ When every task is done but the goal is not, `add.py status` shows
50
50
  - **Define the release steps** — write the milestone's `## Release steps` (merge is one small
51
51
  step among them; PR, asset export, tag/publish are others). These **feed** the release scope —
52
52
  read `release.md` for the cut; loop.md never re-specifies it.
53
- Present the close via `report-template.md` — open with the ARC (goal · done · plan) and
54
- render as a guided choice (recommended next move + described alternatives).
53
+ Present the close via `report-template.md` — open with the ARC (goal · done · plan),
54
+ render as a guided choice **before `milestone-done`/`archive-milestone` run, not after.**
55
55
 
56
56
  ## Reopen is the verb; this loop is the trigger
57
57
 
@@ -47,12 +47,12 @@ Ask only the live ones. Rank: `⚠ <assumption> — lowest confidence because <w
47
47
 
48
48
  Capture each surfaced decision as an **ADR** in `PROJECT.md` **Key Decisions** as it lands.
49
49
 
50
- **Under `autonomy: auto`, auto-complete all four drives in one pass** — lowest-confidence-first. This deepens **drafting**, never the gate: it NEVER skips the human baseline approval — `lock` stays the one decision.
50
+ **Under `autonomy: auto`, auto-complete all four drives in one pass** — lowest-confidence-first. This deepens **drafting**, never the gate — `lock` stays the one decision.
51
51
 
52
52
  ## 3 · Draft to the lock (both paths)
53
53
 
54
54
  1. **Fill the living documentation**: `.add/PROJECT.md` (Domain · Spec · UI/UX · Key Decisions), `CONVENTIONS.md`, `GLOSSARY.md`, `MODEL_REGISTRY.md`, `dependencies.allowlist`, and — for a UI project — `DESIGN.md` (delete if no UI; `design.md`). Brownfield: from code. Greenfield: from interview, gaps flagged `guessed`.
55
- - **Seed personas** (`.add/personas/`): `init` scaffolds `_template.md` (the schema). Author one per role from PROJECT.md + the vendored teacher library `.add/personas-teacher/` (read off-build; engine never fetches), recording the teacher in `source:` and carrying its top `## Playbook` (both optional). Covered by the **baseline approval**; `add.py check` validates; never clobber.
55
+ - **Seed personas** (`.add/personas/`): `init` scaffolds `_template.md` (the schema). **Author one per role** from PROJECT.md + the vendored teacher library `.add/personas-teacher/` (read off-build; engine never fetches) citing the teacher in `source:` and carrying its top `## Playbook` are the two optional parts, not the authoring. Covered by the **baseline approval**; `add.py check` validates; never clobber.
56
56
  2. **Propose, then size it.** Float a **kickoff suggestion** for the first milestone: a **goal** (one sentence), a **flow** (task order), **scenarios** (examples of what ships). Not the frozen `MILESTONE.md`. On their reaction, draft `MILESTONE.md` (read `scope.md`).
57
57
  3. **Create the first task and draft its candidate specification bundle.** `new-task` is allowed pre-lock:
58
58
  ```bash
@@ -76,7 +76,7 @@ Floor: **one human approval per contract**.
76
76
 
77
77
  ## 4 · The one human gate — the baseline approval
78
78
 
79
- Open the report with the ARC per `report-template.md`, render SHAPE then APPROVE as a guided choice, then present `SETUP-REVIEW.md` lowest-confidence-first. They confirm **once** — an explicit yes to the baseline approval; ambient mid-stream agreement is not a confirmation. On that recorded confirmation, you run the lock:
79
+ Open the report with the ARC per `report-template.md`, render SHAPE then APPROVE as a guided choice, then present `SETUP-REVIEW.md` lowest-confidence-first. They confirm **once** — an explicit yes; ambient agreement is not a confirmation. **Never self-stamp a timeout — hold, or re-ask.** On that recorded confirmation, you run the lock:
80
80
 
81
81
  ```bash
82
82
  python3 .add/tooling/add.py lock --by "<name>"
@@ -14,7 +14,7 @@ Then mark `Status: FROZEN @ v1`. Generate a mock + contract tests so dependent
14
14
  work can start before the real code exists.
15
15
  </output_format>
16
16
 
17
- **The freeze is the one approval.** Present the bundle **lowest-confidence first**: the 1–2 points most likely wrong (`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`). Open with the ARC per `report-template.md`, rendering SHAPE then the freeze APPROVE as a guided choice (recommended pick + described alternatives). See `run.md`. The approval also freezes the §5 **Scope (may touch)** allowlist + Strategy declarations.
17
+ **The freeze is the one approval.** Present the bundle **lowest-confidence first**: the 1–2 points most likely wrong (`⚠ [spec|scenario|contract|test] … — because …; if wrong: …`). Open with the ARC per `report-template.md`, rendering SHAPE then the freeze APPROVE as a guided choice (recommended pick + alternatives) — **render before `FROZEN`, then record `Reported: yes` in §3; never on a timeout.** See `run.md`. The approval also freezes §5 **Scope (may touch)** + Strategy.
18
18
 
19
19
  ## The freeze review checklist
20
20
 
@@ -19,6 +19,8 @@ Fill the §6 **Build expectations** block BEFORE Build: OBSERVABLE outcomes deri
19
19
  - [ ] Coverage did not decrease.
20
20
  - [ ] No test or contract was altered during build.
21
21
  - [ ] Every §6 Build expectation is confirmed by real evidence (not just a green test).
22
+ - [ ] §1 rules trace to §2/§4 — an untraced rule is a coverage gap (`add.py audit`'s `rule_coverage_gap`; `check` has detail).
23
+ - [ ] every §3-cited symbol still resolves in the CURRENT tree, not just Ground SHA (§6 Live-verify evidence catches a stale/moved anchor here, not later).
22
24
 
23
25
  If any is false, stop and return to Build.
24
26
 
@@ -42,7 +44,7 @@ A green suite proves tests pass — not that the build EARNED them. Three judgme
42
44
 
43
45
  ## Record exactly one outcome (no silent pass)
44
46
 
45
- Present this gate via `report-template.md`'s ARC, render APPROVE as a guided choice, and reconcile FLAGS with `add.py report --decide`'s open-item count.
47
+ Present this gate via `report-template.md`'s ARC, render APPROVE, and reconcile FLAGS with `add.py report --decide`'s open-item count. **Human-led: render before `gate` and record `Reported: yes` in §6, never self-stamp.**
46
48
 
47
49
  | Outcome | When |
48
50
  |---------|------|
@@ -125,4 +125,5 @@ APPROVE <the question>
125
125
  - **The question is a summary, never the artifact.** A compact SUMMARY · FLAGS block sits in chat immediately before the ask; the question text itself is two lines at most — intent + what "yes" means + flag count — pointing at the report above.
126
126
  - **NEXT is not a second gate.** The single decision stays in APPROVE; NEXT is ranked recommendations only.
127
127
  - **DECIDED never holds a gate-class call.** Security / residue / lowered-autonomy calls escalate in APPROVE.
128
+ - **Recorded, not just performed.** Rendering this template at a gate is recorded, not assumed — TASK.md's `Reported: yes` (§3/§6) is the mechanical trace; `add.py audit` surfaces an unrecorded one (`contract_report_unrecorded` / `verify_report_unrecorded`), a spot-audit the backstop.
128
129
  </constraints>
package/skill/add/run.md CHANGED
@@ -70,6 +70,7 @@ recorded pass is an explicit pass, not a skip).
70
70
  - **The deep check (every gate, do not skim).** If the task produced code, record that every new symbol is referenced (wiring) and that no new dead/unused code was introduced. If it produced prose or non-code, record a semantic read. An unfilled deep check is a **shallow verify**, not an auto-PASS.
71
71
  - **The recorded refute-read (under `auto`).** The earned-green refute-read (`6-verify.md`) is not just run — its **verdict is recorded** in §6 (`EARNED | NOT-EARNED`); `add.py audit` surfaces an unrecorded one as `refute_unrecorded` — one of three shape lints it lists (with `shallow_deep_check` + `risk_unset`) — and a human spot-audit is the backstop. NOT-EARNED routes to `add.py heal`, never an auto-PASS.
72
72
  - **The recorded Advisor 3-lens verdict (under `auto`).** The Advisor 3-lens sweep (security → concurrency → architecture, `6-verify.md`) is recorded in §6 `### Advisor 3-lens verdict`; `add.py audit` surfaces an unfilled block as `advisor_verdict_unrecorded` — a shape lint alongside `refute_unrecorded`.
73
+ - **The rendered gate report (§3/§6).** Report-template.md's ceremony is recorded, not just performed — a `Reported: yes` line in §3/§6; `add.py audit` surfaces an unrecorded one as `contract_report_unrecorded`/`verify_report_unrecorded`; a human spot-audit is the backstop.
73
74
  - **The `advisor-gate-relax` pathway.** A `risk: high` + `sensitivity: mechanical` task whose §6 Advisor 3-lens verdict records Verdict `PASS` and Residue `none` may auto-complete via `add.py gate PASS` **without** a lowered autonomy level. Security and every non-mechanical sensitivity class are never relaxed by this pathway — the high-risk guard still applies.
74
75
  - **Always escalates to a human (never auto-passed):** any **security** finding (HARD-STOP, always);
75
76
  a **concurrency**/timing risk the tests cannot exercise; an **architecture**/layering violation;
@@ -55,6 +55,9 @@ tier hint: top → dag-scheduler, setup-run-mode; mid → the rest
55
55
  - **Spend your strongest model on the critical path.** Critical-path tasks gate the most
56
56
  downstream work; off-path tasks take **mid**. The tier hint is advisory — override when you
57
57
  know a task is harder than its position suggests.
58
+ - **Prefer the named roster per worker** — `add-build` for a tests/build-phase worker, `add-design`
59
+ for design-phase, `add-verify` for verify-phase (full roster + when-to-spawn in advisor.md) — over
60
+ a generic ad-hoc spawn.
58
61
  - **`--json`** (`{ milestone, waves, critical_path, critical_path_len, tiers, blocked }`) feeds
59
62
  a runner that spawns programmatically. `blocked` lists tasks whose dep cannot be satisfied
60
63
  within this milestone; a `dependency_cycle` is refused with the offending members named.
@@ -95,6 +98,10 @@ floor never drops to zero (`run.md:22`). Do not engineer around it.
95
98
  gates this (`engine-merge-base-enforcement`): `add.py wave-verify` before the first merge-back
96
99
  refuses a mismatched/pending echo (`unverified_fork_base`) or off-template ledger
97
100
  (`wave_ledger_malformed`); `add.py check` is the standing monitor.
101
+ - **Materialize gitignored engine content** — `git worktree add` checks out TRACKED files only;
102
+ `.add/tooling` (engine) and `.add/docs` (book) are gitignored and will be ABSENT even when the
103
+ worktree's HEAD matches — copy them in before the worker's first `add.py` call, or its
104
+ `phase`/`advance` commands have no engine to run at all (confirmed 3-for-3 this session).
98
105
  - **Lease + timeout** — record which worker holds which task (wave ledger); a dead worker releases
99
106
  its claim back to READY.
100
107
  - **Failure isolates** — a worker's STOP-and-escalate blocks only its own task; siblings run on, the
package/tooling/add.py CHANGED
@@ -3055,6 +3055,30 @@ def cmd_check(args: argparse.Namespace) -> None:
3055
3055
  f".add/design/captures/{_pname}.<png|svg|…> — render + confirm it "
3056
3056
  "before build (design.md beat 4)"))
3057
3057
 
3058
+ # roster-uninstalled (roster-install-drift): the ADD-managed guideline block cites the agent
3059
+ # roster ("agents/*.md" tail — matches both the shipped `add-method/agents/*.md` attribution
3060
+ # citation and any older phrasing) but the project may have no roster installed at all — never
3061
+ # shipped in the package, synced before this fix, or from a build that regressed the agents/
3062
+ # tree — a dead reference with no signal anywhere. WARN, never red (measure-not-block);
3063
+ # presence-gated on the citation itself — a project whose guideline files don't cite a roster
3064
+ # at all is silently exempt, never retro-flagged.
3065
+ _project_root = root.parent
3066
+ _cites_roster = False
3067
+ for _gname in GUIDELINE_FILES:
3068
+ try:
3069
+ if "agents/*.md" in (_project_root / _gname).read_text(encoding="utf-8"):
3070
+ _cites_roster = True
3071
+ break
3072
+ except OSError:
3073
+ pass
3074
+ if _cites_roster:
3075
+ _agents_dir = _project_root / ".claude" / "agents"
3076
+ if not (_agents_dir.is_dir() and any(_agents_dir.glob("add-*.md"))):
3077
+ warnings.append(("roster_uninstalled",
3078
+ "guideline file(s) cite the agent roster but no `.claude/agents/"
3079
+ "add-*.md` files are installed — run `add.py update` (or re-run the "
3080
+ "CLI installer) to materialize them"))
3081
+
3058
3082
  passed = sum(1 for ok, _, _ in checks if ok)
3059
3083
  failed = len(checks) - passed
3060
3084
  if as_json:
@@ -6037,6 +6061,21 @@ def _freeze_skip_notices(state: dict) -> list[dict]:
6037
6061
  # region only (mirrors _RISK_HIGH_RE's anchoring so a title substring can never look like one).
6038
6062
  _RISK_ANY_RE = re.compile(r"(?:^|·)[ \t]*risk:[ \t]*\S", re.MULTILINE)
6039
6063
 
6064
+ # A single `Reported:` line (report-rendered-trace) — scoped to ONE phase body at a time by the
6065
+ # caller (bodies.get(3, "")/bodies.get(6, "")), so §3 and §6 never cross-contaminate each other.
6066
+ _REPORTED_LINE_RE = re.compile(r"(?m)^Reported:[ \t]*(.*)$")
6067
+
6068
+
6069
+ def _reported_unrecorded(body_text: str) -> bool:
6070
+ """True iff a 'Reported:' line is PRESENT but still an unfilled `<...>` placeholder or blank.
6071
+ ABSENT line -> False (grandfathered — a pre-existing task's TASK.md predates this template
6072
+ field), mirroring _section_unfilled's absent-block convention."""
6073
+ m = _REPORTED_LINE_RE.search(body_text)
6074
+ if m is None:
6075
+ return False
6076
+ val = m.group(1).strip()
6077
+ return (not val) or bool(re.fullmatch(r"<[^>\n]*>", val))
6078
+
6040
6079
 
6041
6080
  def _guarantee_lint_notices(root: Path, state: dict) -> dict:
6042
6081
  """PRESENCE-ONLY, MEASURE-NOT-BLOCK lints SURFACED (never failed-on) by `add.py audit`
@@ -6049,16 +6088,31 @@ def _guarantee_lint_notices(root: Path, state: dict) -> dict:
6049
6088
  refute-record, M4) — the earned-green verdict the AI must record under
6050
6089
  `auto`; ABSENT block grandfathers exactly like shallow. MEASURE-NOT-BLOCK:
6051
6090
  never auto-blocks a gate, only surfaced here for review + a human spot-audit.
6052
- Honest visibility for three verify guarantees; NEVER a finding (audit stays exit 0). PURE — reads
6091
+ rule_coverage_gap[]= this task's OWN §1 Must/Reject IDs have >=1 rule with no §2 scenario tag
6092
+ and no §4 `covers:` line (_rule_coverage_gaps — same opt-in-by-tag-presence
6093
+ grandfather as `add.py check`'s whole-project sweep) — surfaced the moment
6094
+ THIS task reaches verify, not only via a separate `check` invocation someone
6095
+ has to remember to run; `check` still owns the per-rule detail.
6096
+ contract_report_unrecorded[] = §3's `Reported:` line present-but-unfilled (report-rendered-
6097
+ trace) — the freeze report (banner/ARC/SHAPE) was cited by the guide but
6098
+ never recorded as rendered; ABSENT line grandfathers a pre-field task.
6099
+ verify_report_unrecorded[] = §6's `Reported:` line present-but-unfilled — the gate report
6100
+ (banner/ARC) was never recorded as rendered; same grandfather rule.
6101
+ Honest visibility for six verify guarantees; NEVER a finding (audit stays exit 0). PURE — reads
6053
6102
  TASK.md + state only, writes nothing."""
6054
6103
  shallow, risk_unset, refute_unrecorded, sensitivity_unset = [], [], [], []
6055
6104
  advisor_verdict_unrecorded = []
6056
6105
  advisor_reviewer_is_author = []
6057
6106
  advisor_residue_on_mechanical_mis_tier = []
6107
+ rule_coverage_gap = []
6108
+ contract_report_unrecorded = []
6109
+ verify_report_unrecorded = []
6058
6110
  for slug in sorted(state.get("tasks") or {}):
6059
6111
  if (state["tasks"][slug] or {}).get("phase") not in ("verify", "observe", "done"):
6060
6112
  continue
6061
- body6 = _raw_phase_bodies(root, slug).get(6, "")
6113
+ bodies = _raw_phase_bodies(root, slug)
6114
+ body3 = bodies.get(3, "")
6115
+ body6 = bodies.get(6, "")
6062
6116
  hdr = _task_header(root, slug)
6063
6117
  if _section_unfilled(body6, "### Deep checks"):
6064
6118
  shallow.append(slug)
@@ -6066,12 +6120,21 @@ def _guarantee_lint_notices(root: Path, state: dict) -> dict:
6066
6120
  refute_unrecorded.append(slug)
6067
6121
  if _section_unfilled(body6, "### Advisor 3-lens verdict"):
6068
6122
  advisor_verdict_unrecorded.append(slug)
6123
+ if _reported_unrecorded(body3):
6124
+ contract_report_unrecorded.append(slug)
6125
+ if _reported_unrecorded(body6):
6126
+ verify_report_unrecorded.append(slug)
6069
6127
  if not _RISK_ANY_RE.search(hdr):
6070
6128
  risk_unset.append(slug)
6071
6129
  # sensitivity_unset (risk-sensitivity-taxonomy): a verify-reached task with no
6072
6130
  # human-declared sensitivity — MEASURE-NOT-BLOCK, same class as risk_unset.
6073
6131
  if _task_sensitivity(hdr) is None:
6074
6132
  sensitivity_unset.append(slug)
6133
+ # rule_coverage_gap (verify-traceability-glint): this task's own §1 Must/Reject vs
6134
+ # §2/§4 tags — the SAME predicate `check` uses project-wide, scoped to just this task
6135
+ # and surfaced right at verify, not only via a separate whole-project sweep.
6136
+ if _rule_coverage_gaps(bodies.get(1, ""), bodies.get(2, ""), bodies.get(4, "")):
6137
+ rule_coverage_gap.append(slug)
6075
6138
  # advisor_reviewer_is_author / advisor_residue_on_mechanical_mis_tier
6076
6139
  # (advisor-verdict-audit): MEASURE-NOT-BLOCK lints on the filled advisor block.
6077
6140
  # Both require the block to be PRESENT AND FILLED (not just unfilled).
@@ -6105,7 +6168,10 @@ def _guarantee_lint_notices(root: Path, state: dict) -> dict:
6105
6168
  "sensitivity_unset": sensitivity_unset,
6106
6169
  "advisor_verdict_unrecorded": advisor_verdict_unrecorded,
6107
6170
  "advisor_reviewer_is_author": advisor_reviewer_is_author,
6108
- "advisor_residue_on_mechanical_mis_tier": advisor_residue_on_mechanical_mis_tier}
6171
+ "advisor_residue_on_mechanical_mis_tier": advisor_residue_on_mechanical_mis_tier,
6172
+ "rule_coverage_gap": rule_coverage_gap,
6173
+ "contract_report_unrecorded": contract_report_unrecorded,
6174
+ "verify_report_unrecorded": verify_report_unrecorded}
6109
6175
 
6110
6176
 
6111
6177
  def cmd_audit(args: argparse.Namespace) -> None:
@@ -6142,6 +6208,11 @@ def cmd_audit(args: argparse.Namespace) -> None:
6142
6208
  av = glints["advisor_verdict_unrecorded"]
6143
6209
  print(f"audit: advisor_verdict_unrecorded — {len(av)} task(s): {', '.join(av)} "
6144
6210
  f"— record the 3-lens advisor verdict (§6); a spot-audit is the backstop")
6211
+ if glints["rule_coverage_gap"]:
6212
+ rc = glints["rule_coverage_gap"]
6213
+ print(f"audit: rule_coverage_gap — {len(rc)} task(s): {', '.join(rc)} "
6214
+ f"— a §1 Must/Reject has no §2 scenario tag or §4 covers: line "
6215
+ f"(run `add.py check` for the per-rule detail)")
6145
6216
  if glints["sensitivity_unset"]:
6146
6217
  su = glints["sensitivity_unset"]
6147
6218
  print(f"audit: sensitivity_unset — {len(su)} task(s) reached verify with no "
@@ -6155,11 +6226,22 @@ def cmd_audit(args: argparse.Namespace) -> None:
6155
6226
  print(f"audit: advisor_residue_on_mechanical_mis_tier — {len(am)} task(s): "
6156
6227
  f"{', '.join(am)} — mechanical tier with non-none residue and PASS verdict "
6157
6228
  f"is incoherent; consider re-tiering")
6229
+ if glints["contract_report_unrecorded"]:
6230
+ cr = glints["contract_report_unrecorded"]
6231
+ print(f"audit: contract_report_unrecorded — {len(cr)} task(s): {', '.join(cr)} "
6232
+ f"— record the rendered freeze report (§3 `Reported: yes`); a spot-audit is the backstop")
6233
+ if glints["verify_report_unrecorded"]:
6234
+ vr = glints["verify_report_unrecorded"]
6235
+ print(f"audit: verify_report_unrecorded — {len(vr)} task(s): {', '.join(vr)} "
6236
+ f"— record the rendered gate report (§6 `Reported: yes`); a spot-audit is the backstop")
6158
6237
  if not findings and not skips and not glints["shallow"] and not glints["risk_unset"] \
6159
6238
  and not glints["refute_unrecorded"] and not glints["advisor_verdict_unrecorded"] \
6160
6239
  and not glints["sensitivity_unset"] \
6161
6240
  and not glints["advisor_reviewer_is_author"] \
6162
- and not glints["advisor_residue_on_mechanical_mis_tier"]:
6241
+ and not glints["advisor_residue_on_mechanical_mis_tier"] \
6242
+ and not glints["rule_coverage_gap"] \
6243
+ and not glints["contract_report_unrecorded"] \
6244
+ and not glints["verify_report_unrecorded"]:
6163
6245
  print(f"audit: clean ({checked} tasks checked)")
6164
6246
  # MEASURE-NOT-BLOCK: only real findings raise the exit code; notices never do.
6165
6247
  if findings:
@@ -82,6 +82,7 @@ Schema: <tables/fields touched, and access pattern>
82
82
 
83
83
  Glossary deltas: <new domain term(s) this task introduces, `Term: definition` — or "none">
84
84
  Status: DRAFT
85
+ Reported: <yes — the freeze report (banner/ARC/SHAPE) rendered before this froze | no>
85
86
  <!-- The freeze IS the one approval — lead it with the bundle's lowest-confidence flag: the 1–2
86
87
  points most likely wrong across the whole bundle, tagged [spec|scenario|contract|test], each
87
88
  with why + cost (the §1 ⚠ assumptions feed it; a flag may point at a scenario or the contract
@@ -117,6 +118,7 @@ Scope (may touch): `./src/` <fill before the §3 freeze — every file the bui
117
118
  Strategy (ordered batches): <1. … 2. … — the planned build order; guidance, not enforced; preferred architecture/pattern strategies; advise solution/method to resolve issues/implement features>
118
119
 
119
120
  Persona (optional): <name the persona file under `.add/personas/` this build embodies as a domain stance atop SOUL.md — advisory, never lowers a gate; absent = generic>
121
+ Spawn isolation (default): <prefer isolation: "worktree" for any subagent build/verify spawn, not only explicit parallel mode; shared-tree needs a stated reason — see worktree-isolated-spawn-default>
120
122
  Known-problem fixes: <trap → planned fix — the failure modes this build must dodge; guidance, not enforced>
121
123
  Strategy actually used: <fill at VERIFY — the strategy you ACTUALLY used (or "as planned"); harvested into the §7 Decisions (ADR) block as the [AI] build decision>
122
124
  Safety rule (feature-specific): <e.g. debit+credit in one atomic transaction>
@@ -187,6 +189,7 @@ Residue: <none | summary>
187
189
  Binding: <yes — mechanical | advisory — <sensitivity>>
188
190
 
189
191
  ### GATE RECORD
192
+ Reported: <yes — the gate report (banner/ARC) rendered before this outcome recorded | no>
190
193
  Outcome: <PASS | RISK-ACCEPTED | HARD-STOP>
191
194
  If RISK-ACCEPTED -> owner: <name> · ticket: <link> · expires: <date> (never for a security gap)
192
195
  Reviewed by: <name> · date: <date>