Repository navigation
perf(security-issue-deduplicate): decide and render the merge as code - #1707
Merged
Merged
Conversation
A new issue-deduplicate family in tools/security-management takes the
rules of security-issue-deduplicate that are pure functions of tracker
state: the selector (the kept side first, never guessed), the Step 1
checks and CVE rules, the Step 2 field reads and conflicts, the Step 3
merged body, both Step 4 rollup entries, the Step 5 proposal, reply
grammar and per-backend apply order, and the Step 6 recap. Judging the
shared root cause, the headline and analysis, and a merged summary or
widened version range stay with the model.
The merged body is the kept body rewritten field by field through
github-body-field's replace_field, which refuses any rewrite that would
change another field, so the CVE JSON attachment, a project's extra
fields and every unchanged value stay byte-exact.
The numbered-proposal reply grammar moves from cve_allocate to
shared.numbered and the Reporter-notification line to
shared.rollup.notification_line, so both skills use one copy.
SKILL.md becomes a router (6,312 -> 6,029 tokens); every heading and
golden-rule headline is unchanged. The step-1 to step-6 suites become
pytest cases named after each former case; a new step-3-merge-inputs
model suite covers what the model still writes.
Behaviour changes:
- Reporter-supplied CVSS vectors, scores and severity labels are removed
from the appended report mechanically, and listed for the user.
- A dropped report cannot add, end or hide a field: field-ending and
machine-marker lines are escaped, an unmatched </details> is defused,
and a body github-body-field will not decide on is refused.
- A CVE only on the dropped side, a dropped CVE further along than the
kept one, or a tracker without exactly one scope label blocks the merge.
- Both summaries or both version ranges differing needs the model's
merged value; the merge is refused without it.
- The apply plan is refused while a blocker (a CWE conflict) is open.
- A list with a comment ("1,2,3,4 — skip 5 and 6 for now") applies the
list only when the comment names other items to hold them back.
Part of #1672
Generated-by: Claude Opus 5
potiuk
added a commit
that referenced
this pull request
Oct 19, 2026
…s code (#1705) * perf(security-cve-allocate): decide and render the allocation rules as code A new cve-allocate family in tools/security-management takes the rules of security-cve-allocate that are pure functions of tracker state: the selector and its CVE override, the Step 1 blockers, the Step 2 title cascade, the Step 0 API pre-flight and the allocation exits, the Step 3 API proposal, recipe and relay, the paste-back CVE ID, the reporter draft plan and its leak check, the Step 4 numbered proposal and rollup entry, the Step 5 reply grammar and per-backend apply order, and the Step 7 recap. Writing the reporter draft stays with the model, and allocating the CVE with the user. The draft backend choice and the leak scan move from issue_invalidate to shared.drafting, unchanged, so both skills use one copy. SKILL.md becomes a router (7,679 -> 7,324 tokens); every heading and golden-rule headline is unchanged, and the blocker list moved to outcomes/blockers.md. The title cascade leaves the inline Python recipe for `cve-allocate title`, which takes the project's names and tracker prefixes from title-normalization.md. The step-1, 2, 3, 4, 5 and 7 suites become pytest cases named after each former case; a new step-4-draft-body model suite covers the one step the model still owns. Behaviour changes: - The reporter status draft names the bare CVE ID and never the CVE-tool record URL, which a reporter cannot open (editorial guidelines); the canned-response template said the opposite and is fixed. - A malformed or second CVE token in the invocation or the paste-back is refused, never repaired. - Two scope labels, or a CVE tool link field github-body-field will not decide on, block instead of being guessed. - A re-run with the CVE already wired into the field (a partial apply) is a resume, not an "already allocated" blocker. - A draft id is claimed pending in the rollup only after checking Drafts. - An allocation is never re-run automatically; after an expired token it needs a fresh yes. - A free-form reply applies nothing: it is an edit, and the proposal is confirmed again. Part of #1672 Generated-by: Claude Opus 5 * fix(security-cve-allocate): answer the two CodeQL findings - The item-list pattern of the confirmation grammar allowed whitespace on both sides of a whitespace separator, so a reply of many spaced zeros backtracked exponentially (py/redos). The separators are now a comma, `and`, or whitespace alone, which cannot overlap. - A recap test asserted on `dict.pop` (py/side-effect-in-assert); it reads the key instead. Generated-by: Claude Opus 5 * perf(security-issue-deduplicate): decide and render the merge as code (#1707) A new issue-deduplicate family in tools/security-management takes the rules of security-issue-deduplicate that are pure functions of tracker state: the selector (the kept side first, never guessed), the Step 1 checks and CVE rules, the Step 2 field reads and conflicts, the Step 3 merged body, both Step 4 rollup entries, the Step 5 proposal, reply grammar and per-backend apply order, and the Step 6 recap. Judging the shared root cause, the headline and analysis, and a merged summary or widened version range stay with the model. The merged body is the kept body rewritten field by field through github-body-field's replace_field, which refuses any rewrite that would change another field, so the CVE JSON attachment, a project's extra fields and every unchanged value stay byte-exact. The numbered-proposal reply grammar moves from cve_allocate to shared.numbered and the Reporter-notification line to shared.rollup.notification_line, so both skills use one copy. SKILL.md becomes a router (6,312 -> 6,029 tokens); every heading and golden-rule headline is unchanged. The step-1 to step-6 suites become pytest cases named after each former case; a new step-3-merge-inputs model suite covers what the model still writes. Behaviour changes: - Reporter-supplied CVSS vectors, scores and severity labels are removed from the appended report mechanically, and listed for the user. - A dropped report cannot add, end or hide a field: field-ending and machine-marker lines are escaped, an unmatched </details> is defused, and a body github-body-field will not decide on is refused. - A CVE only on the dropped side, a dropped CVE further along than the kept one, or a tracker without exactly one scope label blocks the merge. - Both summaries or both version ranges differing needs the model's merged value; the merge is refused without it. - The apply plan is refused while a blocker (a CWE conflict) is open. - A list with a comment ("1,2,3,4 — skip 5 and 6 for now") applies the list only when the comment names other items to hold them back. Part of #1672 Generated-by: Claude Opus 5
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.
Layer 4a of the security-family deep split (#1672), stacked on #1705 (cve-allocate):
security-issue-deduplicate's rule-shaped steps move into anissue-deduplicatefamily oftools/security-management. Sync (4b) follows separately.What moves to code
selectorclassifyduplicate; the CVE rules (a CVE only on the dropped side → swap,public→ refuse, two CVEs → the kept one at least as far along, the dropped one retracted)fieldsmerge-bodyreplace_fieldrender-rollup-kept,render-rollup-droppedproposal,parse-reply,apply-planrender-recapThe model keeps the root-cause judgement, the headline and analysis, and a merged summary or widened version range when the trackers disagree.
The merged body is the kept body rewritten one field at a time with github-body-field's
replace_field, which refuses a rewrite that would change any other field. The CVE JSON attachment, a project's extra fields and every unchanged value stay byte-exact.shared.numbered(the numbered-proposal reply grammar) andshared.rollup.notification_linemove out ofcve_allocate, so both skills use one copy.SKILL.mdbecomes a router (6,312 → 6,029 tokens); every heading and golden-rule headline is unchanged. The step-1 to step-6 model suites are now pytest cases named after each former case (tests/test_issue_deduplicate.py). A newstep-3-merge-inputsmodel suite covers what the model still writes, and passes 3/3 on a self-eval.Behaviour changes
</details>is defused, and a body github-body-field will not decide on is refused.Spec
security-issue-lifecycledescribes the new family.Part of #1672
Generative AI disclosure
Drafted with Claude Code (Claude Opus 5) and reviewed by the author.
🤖 Generated with Claude Code