@mstar-harness/dsh 3.10.3 → 3.11.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.
Files changed (29) hide show
  1. package/harness-commands/iteration-start.md +1 -1
  2. package/harness-skills/mstar-artifacts/references/plan-quality-bar.md +13 -0
  3. package/harness-skills/mstar-audit/SKILL.md +2 -2
  4. package/harness-skills/mstar-audit/references/codebase-audit.md +53 -4
  5. package/harness-skills/mstar-audit/references/finding-format.md +44 -0
  6. package/harness-skills/mstar-audit/references/security-review.md +194 -32
  7. package/harness-skills/mstar-branch-worktree/SKILL.md +3 -2
  8. package/harness-skills/mstar-dispatch-gates/SKILL.md +7 -0
  9. package/harness-skills/mstar-host/references/cursor.md +1 -13
  10. package/harness-skills/mstar-host/references/omp.md +30 -5
  11. package/harness-skills/mstar-iteration/references/iteration-artifact-boundaries.md +7 -5
  12. package/harness-skills/mstar-iteration/references/iteration-compass-template.md +21 -3
  13. package/harness-skills/mstar-iteration/references/phase-1-prepare.md +37 -3
  14. package/harness-skills/mstar-iteration/references/phase-2-worktree-lease.md +3 -3
  15. package/harness-skills/mstar-iteration/references/phase-3-iteration-close.md +1 -0
  16. package/harness-skills/mstar-iteration/references/phase-6-post-merge-close.md +1 -1
  17. package/harness-skills/mstar-iteration/references/plan-scoped-pm.md +2 -0
  18. package/harness-skills/mstar-phase-gates/SKILL.md +1 -1
  19. package/harness-skills/mstar-roles/references/project-manager/dispatch-and-assignment.md +1 -2
  20. package/harness-skills/mstar-sdd/SKILL.md +1 -13
  21. package/harness-skills/mstar-sdd/references/file-handoffs.md +0 -1
  22. package/harness-skills/mstar-sdd/references/implementer-continuation-prompt.md +0 -1
  23. package/harness-skills/mstar-sdd/references/implementer-prompt.md +0 -1
  24. package/harness-skills/mstar-sdd/references/sticky-implementer-session.md +0 -1
  25. package/harness-skills/mstar-sdd/references/task-reviewer-prompt.md +0 -1
  26. package/harness-skills/mstar-use-cli/SKILL.md +1 -0
  27. package/harness-skills/mstar-use-cli/references/checks-and-lints.md +1 -1
  28. package/harness-skills/mstar-use-cli/references/plan-and-workflow.md +4 -0
  29. package/package.json +1 -1
@@ -59,7 +59,7 @@ Execute **`mstar-host`** → active host 的 **plan-mode bridge**(其 "mstar-i
59
59
 
60
60
  Command-unique 补充(bridge 未枚举):
61
61
 
62
- - **空白脚手架字段**:Direction / Scope / Acceptance Criteria / Non-Goals / Delivery Branch Policy(`iteration_base_branch` / `spec_integration_branch` / `target_branch`)/ Plans / Feedback log / Deferred grill log
62
+ - **空白脚手架字段**:Direction / Scope / Decisions / Open Questions / Acceptance Criteria / Non-Goals / Delivery Branch Policy(`iteration_base_branch` / `spec_integration_branch` / `target_branch`)/ Plans / Feedback log / Deferred grill log
63
63
  - **Build 才勾的 todos**(顺序):`harness-init` → `finalize-compass-plans`(同一 session plan 落成 compass + plans + `status.json` 登记 + 索引)→ review-edit-product-manager → review-edit-architect → review-edit-writing-specialist → `pm-lock` → `integration-branch`
64
64
 
65
65
  ## 非 Plan 路径从这里继续 ↓
@@ -8,6 +8,19 @@ SDD implementers start with a fresh session — they have not seen the Prepare c
8
8
 
9
9
  The plan is the spec. Everything the executor needs must be in the file or reachable from a file path it names.
10
10
 
11
+ ## Prepare-writing bar (Phase 1 editing roles)
12
+
13
+ The Phase 1 editing roles (`product-manager` → `architect` → `writing-specialist`) carry the mirror-image obligation of the principle above: **they are the ones who write the context carrier.** The PM draft and the compass are the artifact a fresh session reads, and a dispatched Phase 1 role works from disk — never from the PM's conversation. A decision that lives only in that conversation is invisible to the role, which will re-derive it wrong.
14
+
15
+ So the draft is held to the same self-containment standard as a plan:
16
+
17
+ - **Context first, depth second.** Locked direction, settled decisions, open questions with owners, non-goal rationale, constraint sources, acceptance seed, branch policy. Coarse detail is legitimate; an *unmarked* hole is not — it has no owner and no place to be discharged.
18
+ - **Every unfinished part carries its owner.** The marker grammar is defined once, in `mstar-iteration/references/phase-1-prepare.md` §1.3 (`TODO(owner: …)`); this file cites it and does not restate it.
19
+ - **An editing role discharges the markers naming it** in its own edit pass, re-owning to `PM` whatever it cannot close, and reports the count.
20
+ - **No role-owned marker survives the compass lock.** Cleared (or explicitly re-owned to `PM` and raised to the user) before compass `status: locked` — never silently dropped.
21
+
22
+ The unowned-`TBD` ban is unchanged at every stage.
23
+
11
24
  ## Quality checklist
12
25
 
13
26
  Before a plan is locked, verify every item:
@@ -61,7 +61,7 @@ Full codebase audit: nine-category fan-out across **`references/audit-playbook.m
61
61
  2. **Simpler explanation** — does a simpler explanation cover the same evidence?
62
62
  3. **Evidence verifiability** — open the cited `file:line` and check it actually supports the claim.
63
63
 
64
- Dispose per the five-state rule (single-pass version — the four dispositions below implement the survey's five-state semantics: uncovered-keep == 未提及保留; never-drop == 全空/null 回流):
64
+ Dispose each attacked finding into exactly one of the four dispositions below:
65
65
 
66
66
  - **Survived** — passes to vet unchanged.
67
67
  - **Refuted** — drop, and record in the index's "considered and rejected" section: `- <finding>: not worth doing because <one line>`.
@@ -90,7 +90,7 @@ Do not write 30 plans nobody asked for. If running non-interactively (no user av
90
90
 
91
91
  The output contract is common; per-variant output shapes live in the variant reference.
92
92
 
93
- - **Full codebase audit**: audit index `README.md` template (findings table, direction, execution order & status, considered-and-rejected, red-team dispositions) and the `mstar audit scaffold` Engine-check callout → **`references/codebase-audit.md`** § Output format. Plan writing → **`## Plan output (all variants)`** below.
93
+ - **Full codebase audit**: audit index `README.md` template (findings table, direction, Coverage table, execution order & status, considered-and-rejected, red-team dispositions, plus the Needs verification and Hardening & checked notes disposition sections) and the `mstar audit scaffold` Engine-check callout → **`references/codebase-audit.md`** § Output format. Plan writing → **`## Plan output (all variants)`** below.
94
94
  - **PR review**: `findings` / `verdict` / `score_pct` / `tally` / `evidence` / `unverified` / `next` / `notes` / `comments` → **`references/pr-review.md`** § Output shape.
95
95
  - Every finding follows **`references/finding-format.md`** — read it before the first finding.
96
96
 
@@ -22,12 +22,12 @@ Audit depth follows the **effort level** (default `standard`; set with `quick` /
22
22
 
23
23
  | | `quick` | `standard` (default) | `deep` |
24
24
  |---|---|---|---|
25
- | Coverage | Recon hotspots only — highest-churn, highest-criticality code | Hotspot-weighted, key packages | Whole repo, every package |
25
+ | Breadth | Recon hotspots only — highest-churn, highest-criticality code | Hotspot-weighted, key packages | Whole repo, every package |
26
26
  | Subagents | 0–1 (sweep directly when feasible) | ≤4 concurrent | ≤8 concurrent, one per category |
27
27
  | Categories | correctness, security, tests | all nine | all nine |
28
28
  | Findings | top ~6, HIGH-confidence only | full table | full table incl. LOW-confidence "investigate" items |
29
29
 
30
- Whatever the level, state in the final report what was *not* audited.
30
+ Whatever the level, record what was examined and what was not in the final report's **Coverage** section (see § Output format) — one row per material review question, never a bare "not everything was audited" disclaimer.
31
31
 
32
32
  Every finding follows **`references/finding-format.md`** — read it before the first finding.
33
33
 
@@ -48,7 +48,15 @@ Plan-file layout, Status block, commit stamp, and handoff follow the shared cont
48
48
 
49
49
  **Excerpts come from your own reads, never from a subagent's report.** Before writing each plan, open every cited file yourself — subagent line numbers and attributions are leads, not facts.
50
50
 
51
- If an audit directory from a previous run exists, **reconcile, don't duplicate**: read its `README.md`, keep numbering monotonic, skip findings already planned or listed as rejected, mark superseded plans stale.
51
+ If an audit directory from a previous run exists, read its `README.md` before planning this run and carry the prior record over under five rules:
52
+
53
+ 1. **Prior `covered` is priority input, not fresh evidence.** Unchanged prior evidence may shape where this run looks, but a unit not re-examined this run is `deferred` with an explicit reference to the prior evidence and a reason — never marked `covered` this run. Do not relabel earlier checks as current work.
54
+ 2. **Prior `deferred`, `blocked` and `out_of_scope` units become current work when now in scope.** They are priority input for this run, never suppression keys.
55
+ 3. **A prior rejected claim suppresses only the exact claim with unchanged relevant evidence and control assumptions.** It never exempts the whole unit; changed evidence reopens the question.
56
+ 4. **Prior quick/scoped/truncated runs contribute only their recorded evidence and gaps; partial or missing prior coverage implies no clean remainder** — missing coverage means unknown, not clean.
57
+ 5. **Match finding fingerprints where present.** A re-considered claim keeps its fingerprint identity even if its disposition changes; legacy findings without fingerprints are compared by evidence and root cause, and never assigned a fabricated identity. The scaffold keeps numbering monotonic and never upserts or re-sorts prior rows; new plans get the next numbers in caller order. Findings already planned or listed as rejected in the prior run are skipped, not re-planned; plans the new run supersedes are marked stale in the index rather than deleted.
58
+
59
+ When finalizing the index, write the **Coverage** section per § Output format — and mind the scaffold ordering documented there, since `mstar audit scaffold` rebuilds the README and does not preserve Coverage.
52
60
 
53
61
  Plans generated from `simplify` / removal findings must carry **behavior-preservation verification gates**: existing tests pass *unmodified*, and characterization tests come first where coverage is thin (playbook §4). When the simplification would touch more than ~500 lines, recommend a codemod/automation pass rather than manual edits.
54
62
 
@@ -64,16 +72,33 @@ Plans generated from `simplify` / removal findings must carry **behavior-preserv
64
72
  | # | Finding | Category | Impact | Effort | Risk | Confidence | Evidence |
65
73
  |---|---------|----------|--------|--------|------|------------|----------|
66
74
 
75
+ The base table has the seven columns above; `Impact` is always prose — what goes wrong and who pays — never a numeric or category label. When at least one displayed finding carries a fingerprint, an optional `Fingerprint` column is appended after `Evidence`; when at least one carries a structured severity, the three columns `Likelihood | Severity impact | Severity` are appended after it (matching `finding-format.md` § Rendering consequences: `# | Finding | Category | Impact | Effort | Risk | Confidence | Evidence [| Fingerprint][| Likelihood | Severity impact | Severity]`). These columns are table-wide: a row without the metadata shows `—` in the new cells, and a table where no row carries it keeps the base header exactly. A fingerprint is optional author-chosen identity per `finding-format.md`; the scaffold never invents one and never re-sorts rows by it.
76
+
67
77
  ## Direction (separate)
68
78
 
69
79
  [2-4 grounded suggestions with evidence and trade-offs]
70
80
 
81
+ ## Coverage
82
+
83
+ | # | Unit (surface × boundary/invariant × subsystem × category) | Status | Evidence / check | Reason / gap |
84
+ |---|---|---|---|---|
85
+ | C1 | order route × owner binding × API × security | covered | `src/orders.ts:42` → verified lookup binds order and actor; unauthorized branch rejects | — |
86
+ | C2 | webhook × signature verification × worker × security | blocked | `src/hooks.ts:18` → found verifier call; deployment key source unavailable | Missing deployed key configuration; see Needs verification lead "webhook provenance" |
87
+ | C3 | export job × tenant scope × worker × security | deferred | — | Not examined: this run's budget was spent on the auth and webhook surfaces; export tenant scope needs its own pass |
88
+
89
+ Coverage is partial. Not examined: export tenant scope. Unresolved: webhook deployment key source. No previous coverage record was available.
90
+
91
+ (When no row is non-covered, close with the gap-free form instead — same rules, no numeric tallies:)
92
+ Coverage is complete for the declared scope. Every material review question has a row and all are covered; no unresolved gaps. No previous coverage record was available.
93
+
71
94
  ## Needs verification
72
95
 
73
96
  [MEDIUM-confidence or runtime-dependent leads — mainly from the Security pass (`references/security-review.md`). One line each; these are not findings and get no plan until verified:]
74
97
 
75
98
  - <lead>: what to verify, how (the exact check), evidence so far (`file:line`).
76
99
 
100
+ **Finding / lead exclusivity.** The same causal claim is either a reportable finding or a Needs-verification lead in the current report — never both. This is a semantic judgment by the author, over the causal claim, not over titles: similar wording is not proof of identity, and different wording does not prove two claims. Nothing enforces this mechanically; the lead carrier has no fingerprint field (a lead's prose may cite one, which the scaffold does not parse). A blocked Coverage row may link a lead, but that does not promote the lead to a finding; a runtime-dependent security claim stays here as requires runtime verification until resolved.
101
+
77
102
  ## Hardening & checked notes
78
103
 
79
104
  [Security-pass leftovers, one line each, no plan unless the user asks. Not findings and not rejected findings — they stay visible so the next run doesn't redo them:]
@@ -96,7 +121,31 @@ Plans generated from `simplify` / removal findings must carry **behavior-preserv
96
121
  - <finding>: <survived / refuted / hallucination-dropped / uncovered-kept>, <one-line reason>
97
122
  ```
98
123
 
99
- > **Engine check (when available):** run `mstar audit scaffold <findings-file> [--dir <out-dir>]` (or `import { scaffoldAuditPlan, validateAuditStatusBlocks } from "@mstar-harness/engine"` in a host hook) to scaffold the `audit-<date>/` plan directory (numbered plan files + README index) from findings, validate the audit Status blocks per **`mstar-audit` SKILL.md** `## Plan output (all variants)`, and redact credentials from audit excerpts. The findings file may be a bare array or `{findings, needsVerification?, hardeningChecked?}`. Disposition policy: a supplied `needsVerification` / `hardeningChecked` set is authoritative and replaces its index section on rebuild (resolved leads are removed by dropping them); an omitted field carries the previous section's entries over, so hand-added security dispositions survive an index rebuild. On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
124
+ ### Coverage contract
125
+
126
+ The Coverage table records which material review questions this run examined, could not examine, or did not attempt. The rows above are a **synthetic example**, not evidence from any particular repository.
127
+
128
+ **Unit.** A row is one *material review question*, described as surface × boundary/invariant × subsystem × category. It is not the Cartesian product of those lists — write the questions a competent reviewer would actually ask, not every combination. For security work the boundary is the control or invariant checked (entry surface × owner binding × API × security). For non-security categories the boundary is the affected operation and property (list rendering × bounded query count × orders UI × perf); do not invent fictitious attackers for `next`, `docs`, `simplify`, or performance work. The `C1`/`C2` labels are author-maintained and report-local — they need not survive another run and imply no generated identity. The descriptive Unit cell is what human reviewers reconcile against.
129
+
130
+ **Statuses.** Exactly five final statuses:
131
+
132
+ | Status | Meaning |
133
+ |---|---|
134
+ | `covered` | Actually examined this run. Requires a reviewed repository `file:line`, the invariant checked, and the observed result — in the cell or in evidence it links. The cited location must be one the author opened this run, and the observed result must be what that read showed — never a location known only from a subagent report or memory. `covered` means examined, **not clean**: the row may carry a confirmed finding. A runtime-dependent unresolved claim makes the row `blocked`, not `covered` with an optimistic footnote. |
135
+ | `blocked` | Attempted but stopped. Record whatever was examined, if anything; when access failed before the first read, the Evidence cell may be `—`. The Reason cell names the concrete missing fact/access/dependency, linking a Needs-verification lead when one exists. |
136
+ | `deferred` | In scope but not examined this run. Evidence cell is `—` or a link to explicitly identified prior evidence — never passed off as this run's work. Reason states why it was not examined: it must name a cause (scope decision, budget, dependency, or access) and must not restate the status. A surface outside the declared scope is `out_of_scope`, not `deferred`. |
137
+ | `out_of_scope` | Material surface deliberately outside the declared scope; Evidence cell is `—` (nothing was examined, so there is nothing to cite); Reason says why. |
138
+ | `not_applicable` | The surface does not exist or the question does not apply; a short recon reference when available, never a fabricated check. |
139
+
140
+ A check is a compact sentence: cited location → question/invariant → observed static result. If an already-authorized, side-effect-free command contributed, identify that command and its result; this adds no new execution permission. Link fuller prose (Needs verification, Hardening & checked notes, a finding) when a cell would become unwieldy — keep each fact in one place rather than duplicating it across cells.
141
+
142
+ **Completeness.** `covered` requires a reviewed path and an actual check/result; every non-covered row requires a concrete reason. Split a materially unexamined sub-question into its own row rather than hiding it under a `covered` parent. A quick/scoped/truncated run states partial explicitly; a broader run never implies unlisted surfaces are clean. Close with an uncounted partial/gap summary that names the gaps already in the table — no numeric tallies, no aggregate path unions, no extra bookkeeping columns. A run with no non-covered rows closes with the gap-free form of the same summary (every material question rowed and covered; no unresolved gaps), subject to the same no-tally rule. Scope completeness and evidence sufficiency remain reviewer judgments, not guarantees delivered by this table.
143
+
144
+ **Scaffold boundary.** `mstar audit scaffold` rebuilds the README index from scratch and carries over only the two security-disposition sections (Needs verification, Hardening & checked notes) — it has **no** coverage input or preservation API and does not validate Coverage. Therefore: read and retain the prior coverage from the existing index **before** invoking the scaffold; after the final scaffold, restore/reconcile the Coverage section into the rebuilt README and write this run's rows. If the scaffold must run again, repeat that ordering. Missing prior coverage is reported as unavailable in the closing summary — never reconstructed from memory.
145
+
146
+ **Deferred enforcement.** The Coverage table is a reviewer-checked authoring structure, not a machine guarantee. Status membership, required cell presence, and reference resolution are deterministic checks, but no existing engine or CLI command performs them: `mstar audit scaffold` neither preserves nor validates Coverage, and nothing else in the harness reads the table. Until a validator ships, a completed Coverage section attests only that the author followed this contract — it is never an "audit complete" certificate, and shape enforcement must not be claimed in prose or added ad hoc.
147
+
148
+ > **Engine check (when available):** run `mstar audit scaffold <findings-file> [--dir <out-dir>]` (or `import { scaffoldAuditPlan, validateAuditFindingGates, validateAuditStatusBlocks } from "@mstar-harness/engine"` in a host hook) to scaffold the `audit-<date>/` plan directory (numbered plan files + README index) from findings, redact credentials from audit excerpts, and run the deterministic finding gates (`validateAuditFindingGates`) before anything is written. The scaffold emits Status blocks that conform to the contract, but it does not re-validate existing plan files: validating audit Status blocks per **`mstar-audit` SKILL.md** `## Plan output (all variants)` is done by a host hook explicitly calling `validateAuditStatusBlocks` (also from `@mstar-harness/engine`) — the CLI command itself never invokes it. The findings file may be a bare array or `{findings, needsVerification?, hardeningChecked?}`; the finding-object field contract — JSON-to-engine mapping, absent-field defaults, string vs structured evidence, fingerprint/trace/severity — is owned by **`mstar-audit` references/finding-format.md § Machine-readable findings file**. Carrier acceptance is engine work; reportability, finding/lead exclusion, and coverage stay reviewer judgement — the engine enforces none of them. Disposition policy: a supplied `needsVerification` / `hardeningChecked` set is authoritative and replaces its index section on rebuild (resolved leads are removed by dropping them); an omitted field carries the previous section's entries over, so hand-added security dispositions survive an index rebuild. On `fail` -> do not proceed; fix and re-run. Skill text below remains authoritative when the runtime is absent.
100
149
 
101
150
  ## Handoff to execution
102
151
 
@@ -42,6 +42,50 @@ When the finding is structural, the Fix sketch names the restructuring move —
42
42
  | `DOCS` | Documentation |
43
43
  | `DIR` | Direction (features & roadmap) |
44
44
 
45
+ ## Machine-readable findings file (`mstar audit scaffold`)
46
+
47
+ The scaffold command `mstar audit scaffold <findings-file> [--dir <out-dir>]` turns a findings file into the numbered plan directory. The file is either a bare JSON array of finding objects or an object `{findings, needsVerification?, hardeningChecked?}`. This section is the contract for the finding objects; what the engine enforces is **carrier acceptance only** — deciding whether a finding is reportable, choosing its severity wording, grouping one root cause, and keeping a claim out of Needs-verification stay reviewer judgement.
48
+
49
+ ### Field mapping and defaults
50
+
51
+ | JSON field | Engine field | Present-value contract | Absent-field behavior |
52
+ |---|---|---|---|
53
+ | `title` | `title` | String, trimmed; visible nonempty content | Usage error, exit 2 |
54
+ | `description` | `impact` | String, trimmed; visible nonempty content. No `impact` JSON alias | Usage error, exit 2 |
55
+ | `priority` | `priority` | `P1` \| `P2` \| `P3` | Usage error, exit 2 |
56
+ | `effort` | `effort` | `XS` \| `S` \| `M` \| `L` \| `XL` | Usage error, exit 2 |
57
+ | `risk` | `risk` | `LOW` \| `MED` \| `HIGH` | Usage error, exit 2 |
58
+ | `category` | `category` | `bug` \| `security` \| `perf` \| `tests` \| `tech-debt` \| `migration` \| `dx` \| `docs` \| `direction` | Usage error, exit 2 |
59
+ | `confidence` | `confidence` | `HIGH` \| `MED` \| `LOW`; explicit value is preserved (previously discarded) | Defaults to `MED` |
60
+ | `evidence` | `evidence` | Array of non-empty strings (legacy free text, rendered as-is) or `{file, line?, description}` location objects; item order preserved; `[]` valid | Defaults to `[]` |
61
+ | `evidence[i].file` | `AuditEvidence.file` | Required safe repository-relative POSIX path | Usage error, exit 2 |
62
+ | `evidence[i].line` | `AuditEvidence.line` | Positive integer when present | Omitted; rendered without a colon or invented line |
63
+ | `evidence[i].description` | `AuditEvidence.description` | Required non-empty string | Usage error, exit 2 |
64
+ | `fingerprint` | `fingerprint` | Non-empty string; passed through untrimmed/unnormalized | Omitted; the engine never invents one |
65
+ | `trace` | `trace` | Array of `{kind, file, line, scope, description}`; all five members required | Omitted |
66
+ | `severity` | `severity` | Object with all of `likelihood`, `impact`, `overall`, each `informational` \| `low` \| `medium` \| `high` \| `critical` | Omitted; never inferred from priority, risk or confidence |
67
+ | `dependsOn` | `dependsOn` | `none`, `plans/NNN-*.md`, or a plan number `NNN` (normalized to `plans/NNN-*.md`); case-insensitive | Omitted; plan renders `none` |
68
+ | `fixSketch` | `fixSketch` | Optional non-empty string | Plan block omitted |
69
+ | `verification` | `verification` | Optional non-empty string | Plan block omitted |
70
+
71
+ A finding is a finding only with non-empty `title` and `description` and valid enums; in `title`, `description`, `priority`, `effort`, `risk`, `category`, `confidence`, `evidence`, `fingerprint`, `trace`, and `severity`, a supplied `null`, wrong type, malformed object, or invalid enum value is a usage error (exit 2, diagnostics name the field path without echoing submitted values), never silent omission or default. `dependsOn` is the one exception: a supplied `null`, non-string, or empty value is treated as absent (the plan renders `Depends on: none`); only a non-empty invalid string is a usage error. Omitting `confidence`, `evidence`, or any optional field is a valid choice, not an error. Authoring guidance such as "2–5 strongest locations" is advice, not an array gate — an accepted carrier is not automatically a reportable finding.
72
+
73
+ ### Deterministic gates the engine runs
74
+
75
+ > **Engine check (when available):** if the harness engine runtime is present, `validateAuditFindingGates(findings)` runs inside `scaffoldAuditPlan` before any file is written, so invalid findings exit 2 with no partial output. Skill text below remains authoritative when the runtime is absent. The gate checks, deterministically and only these:
76
+
77
+ - **Fingerprint** (when supplied): grammar `^[A-Za-z0-9][A-Za-z0-9._:/@+-]*$`, credential rejection (a value redaction would alter is rejected, never rewritten into a different identity), exact case-sensitive uniqueness in the batch, and strict ASCII ordering of the supplied subsequence. Absent fingerprints are skipped; out-of-order input is rejected, never sorted — positions control plan numbers and `dependsOn`. Mixed legacy/enriched batches are accepted. Choosing a stable root-cause identity, grouping one cause, and cross-run matching remain reviewer duties.
78
+ - **Severity**: every rank must be a valid enum value, and `severity.overall` must not exceed `severity.impact`. Nothing else is computed — the gate never infers severity and never proves the claimed impact.
79
+ - **Trace**: non-empty; a single step must be `entrypoint` or `sink`, longer traces must run `entrypoint` → `propagation…` → `sink`. Each step needs a positive-integer `line`, a safe typed path, and visible `scope`/`description`. Topology validation proves format, never reachability — the trace still means what the author claims: where data enters, how it travels, where it lands.
80
+ - **Evidence locations**: object evidence `file` and trace `file` must be repository-relative POSIX paths (no absolute/drive/UNC paths, backslashes, control characters, lone surrogates, empty/`.`/`..` segments, segments ending in a dot or space), and object evidence `line` must be a positive safe integer when present (`audit.finding.evidence.line`). Unsafe paths are never normalized into acceptance, and the engine never checks filesystem existence. Legacy string evidence is free text and is not path-checked.
81
+ - **Text**: `title`, `impact`, supplied `fixSketch`/`verification`, string evidence, structured evidence `description`s, and trace `scope`/`description` must contain visible content (at least one code point outside Unicode whitespace and default-ignorable code points; lone surrogates invalid). Multilingual content is never stripped.
82
+
83
+ Gate diagnostics use stable codes (`audit.finding.fingerprint.*`, `audit.finding.severity.*`, `audit.finding.trace.*`, `audit.finding.path.*`, `audit.finding.evidence.*`, `audit.finding.text.*`) and `findings[index].field` paths only — never raw submitted values, so credential material cannot leak through error output.
84
+
85
+ ### Rendering consequences
86
+
87
+ Structured evidence renders `file:line — description` (or `file — description` when `line` is omitted); string evidence keeps its existing rendering. Supplied `fingerprint`, `severity`, and `confidence` persist into both the plan and the README index (index columns appear when any displayed row carries them, appended after the Evidence column: `# | Finding | Category | Impact | Effort | Risk | Confidence | Evidence [| Fingerprint][| Likelihood | Severity impact | Severity]`). In the plan Status block the `- **Confidence**:` line is emitted for any enriched finding — non-default confidence always persists, and an enriched finding (fingerprint, severity, trace, or object evidence present) keeps even the default `MED`; only a legacy finding without enriched metadata omits the line. When the finding carries evidence, the Status block also includes `- **Evidence**: <first evidence item>` (the first item, rendered like the Evidence bullets); this line feeds the README index Evidence column so the cell survives a no-new-findings rebuild. Supplied `trace` persists into the plan only, as the `## Trace` section — it has no index column. A scaffold re-run with no new findings rebuilds the README index from existing plan files without rewriting them, so persisted metadata survives. The engine neither enforces finding/lead mutual exclusion (a claim is either a finding or a Needs-verification lead by reviewer judgement — the lead carrier `{lead, how, evidence?}` has no fingerprint field) nor validates coverage; both stay with the auditor.
88
+
45
89
  ## Direction findings — adaptations
46
90
 
47
91
  Direction findings (`DIR-NN`) use the same format with two field changes: