* ci: auto-rerun once when runner/spot cancel kills ci jobs
Add rerun.atom.yml as a trusted workflow_run consumer that requests one
`gh run rerun --failed` when completed pull_request/merge_group ci runs
lose leaf jobs to infra cancel (shutdown signal / cancelled runner),
while skipping ordinary assertion failures, stale heads, and ejected
merge-queue entries.
* fix(ci): grant rerun atom read scopes and refuse mixed failures
Add checks/pull-requests read permissions so the helper can fingerprint
infra cancels, and require every non-success leaf to be infra-classified
before authorizing gh run rerun --failed.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): require open PR for live-head stale gate
Stop treating a same-repo branch tip as live-PR evidence. Closed PRs can
leave the source branch at the failed run SHA with no open association;
query open pulls by repository-qualified head ref instead, and cover the
closed-PR + unchanged tip shape in self-check.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): require infra marker for cancel rerun
Bare cancelled jobs without shutdown/spot annotations are ordinary
(manual cancel) and must not authorize gh run rerun --failed.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): ignore aggregate gate jobs in infra-cancel classify
Validate workspace and Runtime summary fail as always() mirrors of leaf
outcomes and never carry runner/spot markers. Counting them as ordinary
blocked pure infra-cancel reruns whenever the workflow still reached the
gate. Exclude those names from classification and cover the shape in
self-check.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fixer: address PR #6453 follow-up items
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): refuse mixed ordinary+infra job annotations
Jobs that record both a real failure annotation and a later runner
shutdown marker must classify as ordinary, not pure infra-cancel, so
gh run rerun --failed cannot auto-retry assertion failures.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): paginate check-run annotations before infra classify
GitHub defaults annotations to 30 results; a later ordinary failure must still
block gh run rerun --failed. Walk pages like paginate_jobs and cover the split
with a multi-page request fixture.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): drop tracked pycache from infra-cancel helper
PerishCode BLOCKING on #6453: remove the accidental CPython 3.14
bytecode under .github/scripts/__pycache__/ and ignore __pycache__/
plus *.py[cod] so local self-check/compile output stays out of git.
* fix(ci): open-PR merge_group freshness; ignore warning annotations
Merge-group infra-cancel retries no longer require the synthetic head to
still sit in the merge queue — workflow_run completed fires after required
checks already ejected it. Freshness is an open PR still associated with
the run (commit→pulls or gh-readonly-queue pr-N ref).
Warning-level annotations (e.g. scopes.ts full-plan fallback) no longer
count as ordinary failures that suppress pure infra-cancel retry.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* fix(ci): match merge_group PR heads and arm rerun e2e Vitest
Compare the live open PR head with the PR head SHA encoded in the
merge-queue branch before authorizing infra-cancel retry, and enroll the
rerun atom surfaces in scopes so PR CI runs the topology self-check.
Generated-By: looper 0.11.8 (runner=fixer, agent=grok-build)
* feat(ci): promote the certain-exempt docs core to merge-queue trust
Split the exempt surface into a certain-tier core (docs/, apps/landing-page/,
.vscode/, .idea/, .github/ISSUE_TEMPLATE/, LICENSE, CODEOWNERS) and the medium
residue (global markdown regex, workflow exacts, nix). A merge-queue group
confined to the core now drops to the unconditional floor lanes instead of
running everything; replaying the last 398 first-parent merges puts that at
12.3% of queue traffic.
The promotion is backed by a new floor-lane guard check, "certain-exempt
surface consumption": no skippable-lane source may reference a certain-exempt
path (dot-relative literals flagged everywhere; bare repo-relative literals
flagged outside test fixtures). guard.ts gains --list-checks as the machine
registry, and the rule-table invariant test now requires every certain rule's
guard field to resolve to a live check.
* docs(ci): record the scope confidence methodology in specs/current/ci.md
The living framework for confidence-tier changes: medium-tier cheap loop vs
certain-tier deliberate loop, the three-sentence promotion discipline, guard
strength levels and floor placement, evidence recipes (replay, offline plan,
queue trace extraction), tooling graduation criteria, and the open questions
deliberately left undecided. Indexed from AGENTS.md and .github/AGENTS.md
required reading.
* fix(ci): narrow certain-exempt fixture handling
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): pin the trae-cli consumption exception to the daemon-lane wiring
The review round established that apps/daemon/tests/runtimes/trae-cli.test.ts
genuinely reads docs/agent-adapters.md. Its exemption from the consumption
guard was justified by a wiring fact (the ci.yml daemon lane runs only
project-watchers.test.ts) stated as prose, which would rot silently if the
lane ever widened. Make the exception conditional on that exact ci.yml needle:
when the daemon lane changes, the exemption disappears and the guard reports
the read, forcing reclassification instead of trusting a stale rationale.
* docs(ci): codify exception-precondition binding in the methodology
Backfill the pattern the first review round produced: guard allowlist entries
justified by local definitional facts may stay prose, but entries justified by
remote mutable facts (lane wiring, gate topology) must be conditional on a
checked precondition so the exception dies loudly with its premise. Records
the trae-cli/daemon-lane needle as the worked example.
* fix(ci): fold static paths in exempt consumption guard
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): require exclusive daemon test wiring
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): recognize daemon pnpm selector forms
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): tokenize daemon workflow test commands
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
---------
Co-authored-by: Looper <looper@noreply.github.com>
* chore(scripts): make root scripts/ test-free and purify the guard entrypoint
Root scripts/ is now source-only, enforced by a new "scripts test-free"
guard check (any *.test.{ts,tsx,js,jsx,mjs,cjs} under scripts/ fails
pnpm guard). The root guard script becomes a pure tsx ./scripts/guard.ts
invocation instead of chaining a hand-maintained node --test file list.
Script behavior-contract coverage follows the boundary e2e/AGENTS.md
already declares for e2e/tests/scripts/: the fork PR approval security
tests migrate there (converted to Vitest, 24 tests passing), and the
remaining script unit tests are deleted — five of them (batch-design-
system-test, check-design-system-package-quality, plugin-previews-diff,
plugin-previews-gc, migrate-to-plugins/example) were orphans no runner
ever executed; the guard-chained checker tests covered logic whose
repo-wide enforcement remains in guard.ts checks. Coverage with a real
test claim gets rebuilt in e2e/tests/scripts/ on demand.
* test(ci): pin characterization goldens for scopes.ts scope detection
Golden tests run scripts/scopes.ts as a subprocess exactly the way ci.yml
does, with gh stubbed through the existing OPEN_DESIGN_GH_NODE_SCRIPT seam
(hermetic stub materialized per run), and pin the complete 20-key output
plan for a matrix of changed-file sets across pull_request,
workflow_dispatch (hot/full), and merge_group events.
They deliberately pin current quirks (skills/*.md arming daemon+web without
the ui-critical fallback; e2e/ui/*.md arming ui_p0 with workspace validation
off; dispatch-hot skipping the workspace_validation re-derivation) so the
upcoming rule-table restructuring can prove behavior preservation
byte-for-byte.
* refactor(ci): restructure scopes.ts into a confidence-tiered rule table
Scope detection becomes data plus a pure evaluator: every changed file is
classified by an additive rule table (union of matched effects, minimum
confidence across matched rules), and an evaluation context brings a trust
threshold — files below it, or matching no rule, escalate fail-closed to
the full radius. Today's behavior is exactly the degenerate case of this
structure (all rules medium, certain set empty): pull_request/hot believes
everything, the merge queue believes nothing and stays full. The
characterization goldens pass unchanged, byte-for-byte.
The exempt surface becomes an explicit empty-radius rule instead of a
special case, so exemptions can be split, rated, and promoted per rule.
Promotion to "certain" requires a guard field naming the enforcing check
(enforced by a rule-table invariant test).
New offline entry points for rule iteration: `plan --context
pr|merge-queue|full --files ...` evaluates without any GitHub environment
and prints { plan, trace }; `rules` lists the table. Every evaluation now
returns a decision trace (per-rule hit counts, per-file escalations, and
an ifTrustAll shadow plan that shows what medium-confidence rules would
have allowed — the evidence stream for future certain-tier promotions);
github-output mode logs it and writes a step-summary table without
touching the frozen 20-key output contract.
The legacy dispatch-hot asymmetry (no workspace_validation re-derivation)
is preserved behind an explicit option and pinned by the goldens.
* feat(ci): evaluate merge-group union diffs at the certain threshold with shadow trace
The merge queue now resolves the queued group's union diff
(compare base_sha...head_sha from the merge_group event payload) and
evaluates it through the rule table at the "certain" trust threshold.
While the certain rule set is empty every file escalates and the queue
keeps running everything — the goldens pin this byte-for-byte — but the
evaluation's ifTrustAll shadow column now records, for every queued
group, what medium-confidence rules would have allowed: the evidence
stream that future certain-tier promotions will cite.
Queue lanes derive from the evaluated outputs (ci_mode stays reported as
"full", but lanes are no longer unconditionally forced), so promoting a
rule to "certain" later is a pure rule-table change with no further
structural work.
Fail-safe behavior is explicit and tested: resolution errors and empty
resolutions fall open to the full plan without failing the scopes job
(queue throughput must never depend on this evaluation), while
pull_request resolution failures keep failing the run as before.
Changed-file resolution no longer filters out removed files (manual hot
runs previously did): deleting a runtime source file must trigger the
same validation scopes as editing it. This is the only behavior change,
and it is strictly fail-closed.
* fix(ci): preserve guard contracts and fail closed on compare limits
Restore the eight guard behavior suites in the e2e script lane and make merge-group compare resolution treat GitHub's 300-file ceiling as incomplete.
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): enforce extension-agnostic script test boundary
Match every suffix after .test. and cover TypeScript, MTS, and non-test filenames in the e2e script suite.
Generated-By: looper 0.11.0 (runner=fixer, agent=codex)
* fix(ci): route script contract tests to e2e
Ensure changes under e2e/tests/scripts arm E2E Vitest with the same daemon and web scope effects as their root script counterparts, and pin the behavior with a PR golden.\n\nGenerated-By: looper 0.11.0 (runner=fixer, agent=codex)
---------
Co-authored-by: Looper <looper@noreply.github.com>
* ci: move nix and docker off the merge validation path
Core ci.yml / Validate workspace / merge_group no longer schedule or require
Nix flake check or Docker image builds. Packaging lives on two standalone
workflows: nix.yml (flake check) and docker-image.yml (PR smoke build +
tag/release publish). Update scopes, topology tests, and agent docs.
* fix(ci): detect Docker publish from release inputs, not workflow_call event
Reusable workflow callers keep their own github.event_name (usually
workflow_dispatch), so matching event_name == workflow_call never fires and
stable GHCR publish would silently smoke-build only. Gate publish on tag push
or non-empty release_version / publish_latest inputs instead.
* fix(ci): keep smoke-only Docker sha tags off the publish path
Gate pr-/manual-sha metadata tags on publish != true so release-stable
workflow_dispatch callers do not push extra manual-sha-* tags to GHCR.