Repository navigation
Closed
Task
Copy link
Labels
agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.Fully specified and briefed; eligible for autonomous pickup from the frontier.area: securitySecurity-relevant: vulnerability, hardening, or disclosure follow-up.Security-relevant: vulnerability, hardening, or disclosure follow-up.priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.Triaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Description
No related issue: follow-up hardening from the Phase 5b review (fix-ci on run-claude-cli).
Problem
Two pr-unblock decisions about fix-ci still read outputs of the read runner's model job (pr-run-activity-read.yml, job run). The 5b review treats those outputs as untrusted, because that job runs PR head code:
fix-ci-subscriptionstarts whenneeds.fix-ci.outputs.lane-class == 'credit-stop' || needs.fix-ci.outputs.credential-present == 'false'(.github/workflows/pr-unblock.yml:395-397).- The read runner's report job skips its check-run post when the run reports
handed-off == 'true'.
A run that misreports these can end with no pr-unblock / fix-ci check posted and no fix-ci-subscription call. fix-ci-dispatch then dispatches again, and the restart cap never counts it. The worst case is repeated lane runs on one PR, which spend prepaid API credits (auto-refill is off, so it costs credits, not a charge).
Fix
- Derive
fix-ci-subscription's start from values the model job cannot write. Two options: the job's own step outcome read through the jobs API, or the fix-ci-context job's result. - Make fix-ci-dispatch count a dispatched run that posted no check toward
fix-ci-restarts, so the loop is capped whatever the run reports.
Acceptance
fix-ci-subscription's start condition reads noneeds.fix-ci.outputs.*value. A test pins this.- A dispatched fix-ci run that posts no check counts toward the restart cap. A test covers it.
Priority: high within the lane-funding follow-ups.
🤖 Generated with Claude Code
Metadata
Metadata
Assignees
Labels
agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.Fully specified and briefed; eligible for autonomous pickup from the frontier.area: securitySecurity-relevant: vulnerability, hardening, or disclosure follow-up.Security-relevant: vulnerability, hardening, or disclosure follow-up.priority: mediumReal value, no hard deadline; normal backlog flow.Real value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.Triaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.A briefed fix or small feature; blast radius bounded by the brief, tests exist.
Type
Fields
No fields configured for Task.
Activity
github-actions commentedon Oct 21, 2026
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Medium
Complexity: Medium
Uncertainty: Known
Flags: none
Blocked by: none
#8890 (comment)
That decision settles the open questions. The fix-ci boxes are done. What remains is the three fix-docs dispatch-cap boxes: no re-dispatch after a completed run without a check, one retry for a lost run, and no dispatch slot for a run stopped at the trigger gate. Each needs a test.
Automated triage, applied by the lanes App.
kyle-sexton commentedon Oct 22, 2026
Scope widened after the #8964 security pass (fix-docs moved into pr-unblock):
fix-docs-subscriptionrepeats the same start condition: it readsneeds.fix-docs.outputs.lane-classandcredential-present(.github/workflows/pr-unblock.yml:516-517, fallback input at:532, as of feat(pr-pipeline): run fix-docs on run-claude-cli with an apply-patch push job #8964 head e89dc01). Its start must come from trusted values too.fix-docs-dispatch.mjsmarks a PR handled only when it finds apr-unblock / fix-docscheck run (:145-147,:187-188). A successful dispatch marks nothing (:199-212), and the in-flight guard skips only runs that are not completed (:177-181). A fix-docs run that ends without posting its check is therefore dispatched again on every push to main, with no per-PR cap. Fix: treat a completedpr-unblock fix-docs #<n>run (runTitle) as handled.Acceptance additions:
fix-docs-subscription's start condition reads noneeds.fix-docs.outputs.*value. A test pins this.Lands right after #8964 and before Phase 7.2, so the address-feedback and review-dependency subscription jobs don't copy the pattern.
kyle-sexton commentedon Oct 22, 2026
Security review findings on #8964 (all LOW, all assigned here):
handed-off=true(pr-run-activity-read.yml:2424,:2534-2543), the report job posts no check. The PR is then dispatched again on every push to main, about once per PR per push and at most 2 per push. At last week's main push rate that is up to about 356 runs a day, each spending prepaid API credits. Precondition: a steered model on a listed author's PR. Fix: record the dispatched head at dispatch time (fix-docs-dispatch.mjs:212), or pass a base-derived head so the report posts a neutral not-assessed check.:160,:175), so two such PRs block fix-docs for every other PR. No model spend. The same fix covers it.fix-docs-subscriptionstarts on run-job outputs a forged run can set (pr-unblock.yml:516-517,:532), the same pattern as fix-ci. It widens no credential reach and triggers no metered charge (usage credits stay off).fix(pr-pipeline): start fix-docs-subscription on a jobs-API handoff read
fix(pr-pipeline): label fix-docs-subscription fallback: handoff
fix(pr-pipeline): take apply-docs-patch inputs from the scan job
kyle-sexton commentedon Oct 25, 2026
Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.
To hold this issue again, add
needs-human(orstatus: needs-decision) and say why in a comment.22 remaining items
kyle-sexton commentedon Oct 27, 2026
Released for re-triage under the owner's standing direction (2026-10-27): a person is involved only for "1. A change to the original intent or vision. 2. A finding during implementation ... that changes the intent, vision or primary design. 3. A real HIGH/CRITICAL security or cost risk", where cost is anything that can bill (Azure, GitHub larger runners or private-repo Actions, paid storage, plan or seat changes) and model usage under the subscriptions or API credits is not cost. None applies here. The hold label came off and intake triage runs again; an open blocked-by edge, if any, makes admission wait for that blocker.
To hold this issue again, add
needs-human(orstatus: needs-decision) and name which of the three applies.github-actions commentedon Oct 27, 2026
The triage sweep dispatched intake triage for this issue (attempt 1 of 2).
[-]pr-unblock: derive fix-ci-subscription's start and the restart cap from trusted values[/-][+]pr-unblock: derive `fix-ci-subscription`'s start and the restart cap from trusted values[/+]kyle-sexton commentedon Oct 30, 2026
Decision recorded.
The fix-ci part landed in #9363 (
e5fd363e05). The three fix-docs criteria from decision comment 6424948616 are still open, so this issue stays open for them. They count fix-docs runs toward a dispatch cap. That cap is a loop breaker, a safety limit that stays active under the owner's standing direction §10.fix-ci-subscription's start condition reads noneeds.fix-ci.outputs.*value. A test pins this." Itsif:reads onlyneeds.fix-ci-handoff.outputs.posted(.github/workflows/pr-unblock.yml:2210-2214), pinned inworkflow-gates.test.mjs. Landed in fix(pr-pipeline): derive fix-ci's fallback, restart count and head binding from trusted jobs #9363 (e5fd363e05).fix-ci-unreportedposts a fix-ci failure "which counts toward fix-ci-restarts" (pr-unblock.yml:2582-2590), covered incallers.test.mjs. Landed in fix(pr-pipeline): derive fix-ci's fallback, restart count and head binding from trusted jobs #9363 (e5fd363e05).cancelled,timed_outorstartup_failure) without a check is dispatched once more, and not after a second such run. A test covers both. (decision comment 6424948616, unchanged)#10455 (
fc07a5d179, for #9247) added a per-head fix-docs cap on main. It stops a head afterlimit-stops-per-headruns (default 3) whose broker-allowed job succeeded (.github/scripts/pr-unblock/fix-docs-dispatch.mjs:284-305). That does not meet these three boxes as written. It allows three runs, not one. It does not treat a lost run (cancelled,timed_outorstartup_failure) differently from other runs. A run that stops at the trigger gate does not count toward the cap, so the PR is dispatched again on every run. The PR that closes this issue checks each box against that code.The
status: needs-decisionhold comes off: the body says the worst case "costs credits, not a charge", and §3 lists "each account's promotional $200 API credits" under "Not cost, so spend it freely".melodic-automation-lanes commentedon Oct 30, 2026
Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.
Intended outcome: fix-docs-dispatch.mjs treats a completed fix-docs run that posted no check as handled, with one retry for a lost run, so a trigger-gate stop no longer takes a dispatch slot.
Acceptance criteria
External state: none
Related work
Sources read
Automated refinement by the lanes App. Admission counts only criteria a listed human wrote: to confirm these, post them as your own comment whose first line is
**Decision recorded.**, which sends the issue back through intake.