Skip to content

Security fix: publish spec-size fixes through staged text - #651

Merged
JacobStephens2 merged 8 commits into
mainfrom
issue-646
Oct 10, 2026
Merged

JacobStephens2 merged 8 commits into
mainfrom
issue-646

Conversation

@JacobStephens2

@JacobStephens2 JacobStephens2 commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

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 by edges must name earlier
Tickets only.

publish (public, spec-size)
  pre-creation window sweep → fail_on_side_effects on any leak
  parse_staged_spec_proposal (all text validated before anything is created)
    parse_blocked_by (only earlier Tickets; forward/cyclic edges rejected)
  create top issue + Tickets
  add_sub_issue + add_blocked_by links
  post-linking window sweep (unlinked_issues) → fail_on_side_effects on any leak
  post-publish checks (open, new, labels, text)

Evidence

  • Before: the review's cyclic-spec probe
    (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.
  • Focused runs: 5/5 staged_spec* unit tests pass (incl. the new forward-edge
    case in staged_spec_rejects_bad_blocking_edges), 1/1 new integration test
    passes, cargo fmt --check passes,
    cargo clippy --all-targets -- -D warnings passes.
  • Full cargo test: exit 0, every target ok, 0 failed.

Seams under test: the secure security-fix staged-spec publish path
(integration seam, tests/security_run.rs) and parse_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-triage issue was filed: every decline below is the
review's own engineering call, not a Spec or Day shift decision, and no open
issue already covers any of them.

  • Standards S1 (Duplicated Code, judgement): api_add_sub_issue and
    api_add_blocked_by in tests/fakes/gh.rs:724 / :758 share a shape.
    Declined: each mirrors a distinct GitHub endpoint (sub_issues vs
    dependencies/blocked_by); extracting one helper would couple two adapters
    that change for different upstream reasons.
  • Standards S2 (Duplicated Code, judgement): parse_staged_proposal
    (src/security/fixing.rs:381) and parse_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.
  • Standards S3 (Primitive Obsession, weak judgement): blocked_by: Vec<usize>
    (src/security/fixing.rs:192). Declined: repo idiom overrides — u64 /
    usize / &str are pervasive across src/github.rs for issue identity.
  • Spec 1 (blocking links never read back against the native graph): the code
    fact holds — test -n "$(grep -n 'blockers' src/security/fixing.rs)"
    exits 1. Declined as a fix: add_blocked_by errors propagate via ?
    (src/security/fixing.rs:327-329), so a failed edge aborts publishing
    rather 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.
  • Security (no introduced findings, no fix): reviewed the staged-spec publish path against the skill's data-isolation and agent-output guidance: 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 the security-fix prompt. All staged text is validated with check_public_fix_text before any public issue exists; pre-creation and post-linking window sweeps close side-effect issues and fail loudly; forward/cyclic Blocked by edges are rejected. Evidence: 5/5 staged_spec* unit tests pass; 8/8 spec-path security_run integration 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.md and
.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

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
JacobStephens2 marked this pull request as ready for review October 10, 2026 19:52
@JacobStephens2
JacobStephens2 merged commit bb2aa67 into main Oct 10, 2026
17 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-646 branch October 10, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security fix: publish spec-size fixes through staged text

1 participant