feat(gate): the brief's threat model on the plan side (decision 164, 218, 220)
plan-gate.mjs --record --brief <brief.md> (a known flag; its value is kept
out of the positional arguments, a missing value is a usage error) applies
the brief's threat model to the deduped findings before countRound when
threat-model.mjs usable() says it may: a backed finding (Voyage's own
security finding whose threat_model_ref equals an Outside: line's text)
leaves the counted set and the stop rule and goes to the new optional
verdict field known_outside ({id, rule_key, text, line}), carried to later
rounds until a reviewer marks it resolved or it is reported again under its
id. The verdict stores brief_path (carried when a later round has none).
The --record line adds known_outside (a count) and threat_model
({applied, why}): a threat model that is not usable backs nothing, every
security finding counts, and the output says why. extractVerdict
shape-checks both new fields.
The bare gate re-reads the brief at brief_path each run: an entry still
backed is a warning, PLAN_GATE_KNOWN_OUTSIDE; one no longer backed (line
gone, approval stale or not logged, brief unreadable, no brief_path, or not
a Voyage security finding) stops the plan, PLAN_GATE_OUTSIDE_NOT_BACKED: it
counts in full. gatePlan takes an optional threatModel for tests.
plan-review-dedup keeps threat_model_ref on a merge only when every merged
copy carries the same one; the S160 known issue is fixed: a null in a
reviewer's findings list is skipped instead of crashing the CLI.
plan-critic and scope-guardian: a security finding needs a concrete attack
path and high confidence (Claude Code's threshold, 167), uses
SECURITY_INJECTION or SECURITY_RISK, and quotes the Outside: line's text in
threat_model_ref when one applies; the json template carries the field.
/trekplan Phase 9 passes the brief path to plan-critic and --brief to
--record. Handover 4 names the two fields, the two codes and the flag.
Part 2, step 2.4 of the E plan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5cb2918baa
commit
98171d7d3b
10 changed files with 612 additions and 26 deletions
|
|
@ -291,7 +291,15 @@ implementation catches nothing, so the finding stays major. Give
|
|||
|
||||
A security finding uses the catalogue's security `rule_key`
|
||||
(`SECURITY_INJECTION`, or `SECURITY_RISK` when no narrower key fits); the
|
||||
engines' key is never yours.
|
||||
engines' key is never yours. Raise one only with a concrete attack path (who
|
||||
sends what, through which step, to what effect) and high confidence, Claude
|
||||
Code's own threshold for a security finding (decision 167); a weakness with no
|
||||
such path is no security finding. When the brief has a `## Threat Model` and
|
||||
the attack path is one an `Outside:` line of it leaves out, put that line's text
|
||||
(after `Outside: `) in `threat_model_ref`, exactly as the brief writes it: the
|
||||
plan gate then lists the finding as a known issue instead of counting it,
|
||||
while the brief's intent approval is current. Otherwise leave
|
||||
`threat_model_ref` out, and the finding counts.
|
||||
|
||||
Your rating decides what happens next: `/trekplan` records your findings with
|
||||
`plan-gate.mjs --record`, and the plan gate stops the plan while any BLOCKER
|
||||
|
|
@ -384,7 +392,7 @@ this block inline *is* the hand-off; do not attempt to write a file.
|
|||
{ "id": "<40-hex id from the current ## Critic Verdict>", "resolved": false }
|
||||
],
|
||||
"findings": [
|
||||
{ "file": "<plan path or source file>", "line": 0, "line_end": 0, "rule_key": "<dimension/short-id>", "severity": "blocker|major|minor", "text": "<one-line finding>", "lowered_from": "major", "caught_by": "<the named test, Regression: command or gate>" }
|
||||
{ "file": "<plan path or source file>", "line": 0, "line_end": 0, "rule_key": "<dimension/short-id>", "severity": "blocker|major|minor", "text": "<one-line finding>", "lowered_from": "major", "caught_by": "<the named test, Regression: command or gate>", "threat_model_ref": "<the text of the brief's Outside: line, exactly>" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
|
@ -404,7 +412,9 @@ finding the current `## Critic Verdict` lists; `resolved` is `true` or
|
|||
`false`. `line_end` (optional) is the last line of a cited range, an integer
|
||||
≥ `line`. `lowered_from` and `caught_by` go only on a finding lowered by rule
|
||||
B: `"lowered_from": "major"`, and `caught_by` names the test, `Regression:`
|
||||
command or gate that will fail on it; omit both otherwise.
|
||||
command or gate that will fail on it; omit both otherwise. `threat_model_ref`
|
||||
goes only on a security finding outside the brief's threat model: the text of
|
||||
its `Outside:` line, exactly; omit it otherwise.
|
||||
|
||||
Be specific. Reference exact plan sections, step numbers, and file paths.
|
||||
Never use "generally" or "usually" — cite the specific problem in this specific plan.
|
||||
|
|
|
|||
|
|
@ -109,7 +109,15 @@ implementation catches nothing, so the finding stays major. Give
|
|||
|
||||
A security finding uses the catalogue's security `rule_key`
|
||||
(`SECURITY_INJECTION`, or `SECURITY_RISK` when no narrower key fits); the
|
||||
engines' key is never yours.
|
||||
engines' key is never yours. Raise one only with a concrete attack path (who
|
||||
sends what, through which step, to what effect) and high confidence, Claude
|
||||
Code's own threshold for a security finding (decision 167); a weakness with no
|
||||
such path is no security finding. When the brief has a `## Threat Model` and
|
||||
the attack path is one an `Outside:` line of it leaves out, put that line's text
|
||||
(after `Outside: `) in `threat_model_ref`, exactly as the brief writes it: the
|
||||
plan gate then lists the finding as a known issue instead of counting it,
|
||||
while the brief's intent approval is current. Otherwise leave
|
||||
`threat_model_ref` out, and the finding counts.
|
||||
|
||||
Your findings go through `plan-gate.mjs --record` with plan-critic's; an open
|
||||
blocker or major stops the plan. `severity` is exactly `blocker`, `major` or `minor`;
|
||||
|
|
@ -174,7 +182,7 @@ this block inline *is* the hand-off; do not attempt to write a file.
|
|||
{ "id": "<40-hex id from the current ## Critic Verdict>", "resolved": false }
|
||||
],
|
||||
"findings": [
|
||||
{ "file": "<plan path or source file>", "line": 0, "line_end": 0, "rule_key": "<creep|gap|dependency|...>", "severity": "blocker|major|minor", "text": "<one-line finding>", "lowered_from": "major", "caught_by": "<the named test, Regression: command or gate>" }
|
||||
{ "file": "<plan path or source file>", "line": 0, "line_end": 0, "rule_key": "<creep|gap|dependency|...>", "severity": "blocker|major|minor", "text": "<one-line finding>", "lowered_from": "major", "caught_by": "<the named test, Regression: command or gate>", "threat_model_ref": "<the text of the brief's Outside: line, exactly>" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
|
@ -193,7 +201,9 @@ finding the current `## Critic Verdict` lists; `resolved` is `true` or
|
|||
`false`. `line_end` (optional) is the last line of a cited range, an integer
|
||||
≥ `line`. `lowered_from` and `caught_by` go only on a finding lowered by rule
|
||||
B: `"lowered_from": "major"`, and `caught_by` names the test, `Regression:`
|
||||
command or gate that will fail on it; omit both otherwise.
|
||||
command or gate that will fail on it; omit both otherwise. `threat_model_ref`
|
||||
goes only on a security finding outside the brief's threat model: the text of
|
||||
its `Outside:` line, exactly; omit it otherwise.
|
||||
|
||||
## When to use — examples
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue