Repository navigation
Security fix: publish spec-size fixes through staged text - #651
Merged
Merged
Conversation
Spec-sized public Security fixes now stage their proposed Spec text (top issue plus Tickets with blocking edges) for validation, and thirdshift creates the issues and their native sub-issue and blocked-by links from the staged text. A rejection creates nothing, and a publishing session that creates a public issue on the side fails loudly with the leak closed, as the single-fix staged path does. Private bigger fixes keep the session-created path. Closes #647
Standards review finding: add_sub_issue and add_blocked_by repeated the database-id lookup plus single-field POST shape. Both delegate to a private post_by_id helper now.
Stage spec proposal text and validate before creating public issues
After the staged spec and its Tickets are created and linked, re-sweep the publishing session window. Anything in it that is neither the spec nor one of its Tickets is a side-effect leak outside the validated staged path: close it and fail loudly, as the pre-creation sweep does.
…648) The staged-spec Blocked by trailer parsed only its first line, silently dropping a stated ordering edge while every other malformation rejects the staged text. Reject non-blank lines after the trailer's first line. Rename fail_on_side_effects sides to leaks, the term the surrounding comments use.
Sweep spec publish session for unlinked public issues
parse_blocked_by accepted any in-range Ticket position except self-edges,
so a staged spec could name later Tickets as blockers or form a cycle and
still publish. A cyclic spec dispatches Tickets that can never unblock.
Validation now fails closed unless every edge names an earlier Ticket, as
the staged format ('each later Ticket naming the positions of the Tickets
that block it') requires.
Keeps the Spec review's cyclic-rejection integration test and a forward-edge
unit case.
JacobStephens2
marked this pull request as ready for review
October 10, 2026 19:52
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.
Summary
Spec #646 publishes spec-size Security fixes through staged text validated
before any public issue exists. Its Tickets both landed on
issue-646:#647 (stage + validate the Spec proposal, thirdshift creates the issues and
their native links) and #648 (pre- and post-publish window sweeps that close
and loudly fail on any session-created side-effect issue). The code review
added one fail-closed fix on top: staged
Blocked byedges must name earlierTickets only.
Evidence
(
a_staged_spec_with_cyclic_blocking_edges_is_rejected_before_creating_anything)FAILED on the pre-fix code — a 1↔2 mutual-block staged spec published
issues 8, 9 and 10 instead of being rejected:
a rejected staged spec must not create a public issue: {"10":..., "8":..., "9":...}.After: the test passes; staged forward/cyclic edges are rejected before
thirdshift creates anything.
staged_spec*unit tests pass (incl. the new forward-edgecase in
staged_spec_rejects_bad_blocking_edges), 1/1 new integration testpasses,
cargo fmt --checkpasses,cargo clippy --all-targets -- -D warningspasses.cargo test: exit 0, every targetok, 0 failed.Seams under test: the
secure security-fixstaged-spec publish path(integration seam,
tests/security_run.rs) andparse_staged_spec_proposal/parse_blocked_by(unit seam,src/security/fixing.rs).Merge Danger
Door: two-way — a revert restores the previous publish path; validation now
rejects bad staged text before any public issue exists, so there is nothing
half-published to unwind from the fix itself.
Blast Radius: security-fix publishing — public spec-size path only. The
single-fix staged path and the private session-created path are untouched
(the ordering guard only narrows what staged text validates).
Unaddressed findings
Each Standards finding or Spec finding the review chose not to fix, with what
refutes it. No
needs-triageissue was filed: every decline below is thereview's own engineering call, not a Spec or Day shift decision, and no open
issue already covers any of them.
api_add_sub_issueandapi_add_blocked_byintests/fakes/gh.rs:724/:758share a shape.Declined: each mirrors a distinct GitHub endpoint (
sub_issuesvsdependencies/blocked_by); extracting one helper would couple two adaptersthat change for different upstream reasons.
parse_staged_proposal(
src/security/fixing.rs:381) andparse_staged_spec_proposal(:209)share a head-parsing shape. Declined: the spec head carries ticket-trailer
grammar the single path lacks; sharing a helper would tangle two formats
that fail for different reasons.
blocked_by: Vec<usize>(
src/security/fixing.rs:192). Declined: repo idiom overrides —u64/usize/&strare pervasive acrosssrc/github.rsfor issue identity.fact holds —
test -n "$(grep -n 'blockers' src/security/fixing.rs)"exits 1. Declined as a fix:
add_blocked_byerrors propagate via?(
src/security/fixing.rs:327-329), so a failed edge aborts publishingrather than dispatching silently — there is no silent-drop path to catch.
Neither Stage spec proposal text and validate before creating public issues #647 ("validate it before creating any public issues") nor Sweep spec publish session for unlinked public issues #648
(window sweep) asks for native-graph read-back, and the pre-existing private
path never verified blockers either; a read-back would be new behaviour
beyond the Spec. Adjacent but distinct: Decide staged-issue fate when the post-linking spec sweep fails #655 covers staged-issue fate when
the post-linking sweep fails, not link verification.
publish_staged_spec/parse_staged_spec_proposal/parse_blocked_by(src/security/fixing.rs),add_sub_issue/add_blocked_by/post_by_id(src/github.rs), and thesecurity-fixprompt. All staged text is validated withcheck_public_fix_textbefore any public issue exists; pre-creation and post-linking window sweeps close side-effect issues and fail loudly; forward/cyclicBlocked byedges are rejected. Evidence: 5/5staged_spec*unit tests pass; 8/8 spec-pathsecurity_runintegration tests pass, including the cyclic-rejection probe and the side-effect-leak probe. No proof-of-concept demonstrated a boundary violation, so this review changed no source, added no test, and made no commit.Review coverage: the Standards and Spec reviewers each read all 7 changed
files (
prompts/security-fix.md,site/prompts/index.html,src/github.rs,src/prompt.rs,src/security/fixing.rs,tests/fakes/gh.rs,tests/security_run.rs). No changed file left unread.Full per-axis reports:
.thirdshift-review-uSwFnb/standards.mdand.thirdshift-review-uSwFnb/spec.md(scratch, git-excluded).Closes #646
Security review outcome
No unaddressed introduced findings.
Tickets
Built with muse · default model · default effort