Skip to content

fix(ci): restructure the Pi job graph - full suite, one canonical job, deadlines, advisory canary#423

Merged
SUaDtL merged 4 commits into
mainfrom
fix/ci-pi-job-structure
Jul 25, 2026
Merged

fix(ci): restructure the Pi job graph - full suite, one canonical job, deadlines, advisory canary#423
SUaDtL merged 4 commits into
mainfrom
fix/ci-pi-job-structure

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Four CI-structure defects around the Pi jobs, fixed together because they all reshape the same job graph in .github/workflows/ci.yml. This lane is CI-config, so the tests are assertions in .github/scripts/test_ci_impact.py (WorkflowContractTest, extended in the file's existing style) plus the pre-existing pi_ci_contract_violations() oracle in .github/scripts/test_pi_package.py.

Closes #405
Closes #390
Closes #399
Closes #381


What changed

#405 — run every Pi adapter suite in required PR CI

Required CI named 6 of the 23 committed plugins/ca-pi/tools/test/*.test.ts files. The other 17 (policy, plan-mode, dispatch, background-jobs, activity, doctor, footer, notices, runtime-resolver, windows-supervisor, security, farm, compaction, child-env, final-arguments, process-tree, runner-isolation) could regress with every required merge-readiness check green.

The new canonical Pi job runs an unfiltered npm test. test_ci_impact.py now computes the partition from the workflow text — a bare npm test in a required Pi job covers the whole suite, a filtered npm test -- test/a.test.ts covers only what it names — and fails when any committed file is unassigned. A second test proves the contract bites: neutering the unfiltered run must leave files unassigned.

File-granular assignment is not enough, and review caught that. Two further holes are now closed:

  1. A file can be "assigned" while its own gate keeps it from running. activation.test.ts:388 is test.skipIf(process.platform !== "win32"); an ubuntu-only lane reports the file as covered and skips the case. So a second contract asserts that every file which branches on the live process.platform runs in a job that fans out over all three operating systems. It is asserted independently in test_ci_impact.py (os_matrix_pi_test_files) and in pi_ci_contract_violations(), both deriving the set from the sources rather than from a hand-kept list — both would have to be wrong to lose the coverage.
  2. A file can be "assigned" while every test inside it is disabled. A third contract forbids a static .skip / .todo / .only anywhere in the committed Pi suite. (.only is included because it silently mutes every sibling; .fails is deliberately allowed — it executes the body and asserts it throws, so it is a real verdict.) A genuine platform gate must be written as .skipIf / .runIf, which contract 1 then holds to running somewhere the gate opens.

Local evidence that the previously-omitted set is runnable and green:

$ npx vitest run test/activity.test.ts test/background-jobs.test.ts test/dispatch.test.ts \
    test/doctor.test.ts test/footer.test.ts test/notices.test.ts test/plan-mode.test.ts \
    test/policy.test.ts test/runtime-resolver.test.ts test/windows-supervisor.test.ts
 Test Files  10 passed (10)
      Tests  222 passed (222)

#390 — factor host-independent Pi checks out of the six-cell matrix

The 3 OS x 2 Pi-version matrix re-ran package-metadata checking, typecheck, the deterministic Vitest suites, the static security/parity scripts, the bundle rebuild + staleness gate, the release package contract, and a 100-sample benchmark once per cell — 1,423 runner-seconds on run 29870271440.

New job ca-pi-checks ([CHECK] | [PI ] | Host-independent adapter contract), one cell on ubuntu-latest, owns:

  • python tools/build-host-packages.py --check
  • npm run typecheck
  • npm test (unfiltered — see Run every Pi adapter suite in required pull-request CI #405)
  • python .github/scripts/test_pi_security.py
  • python .github/scripts/test_pi_parity.py
  • npm run build + the committed-bundle staleness gate
  • python .github/scripts/test_pi_package.py
  • python .github/scripts/pi_benchmark.py --samples 100

The partition, stated explicitly

The issue's AC is "keep every test whose behavior genuinely depends on the installed Pi version or operating system in the matrix." An earlier revision of this PR got that wrong and moved activation.test.ts / commands.test.ts out of the matrix; review caught it. The rule now applied — and enforced by the two contracts above, not by a list:

shape host-dependent? why
test.skipIf(process.platform !== "win32")(...) yes the whole test is skipped on the wrong runner
process.platform === "win32" ? "junction" : "dir" yes a different operating-system primitive is exercised
buildChildEnv({ platform: "win32", ... }) no the platform is injected; both branches run everywhere
runtime: { ..., platform: process.platform } no forwarded into a pure function; same code on every host

Applying it to the committed tree gives 11 host-dependent files. bridge, package, process-tree and runner-isolation are already re-run per cell by test_pi_platform_contract.py; the remaining seven — activation, background-jobs, commands, plan-mode, runtime-resolver, security, windows-supervisor — are executed by a new matrix step. child-env, compaction, status and tool-guard carry no live-platform comparison at all and run once on ca-pi-checks.

ca-pi-tools therefore keeps: the installed-Pi admission boundary (npm test -- test/package.test.ts), the platform-gated Vitest set, live package RPC activation (test_pi_package.py --rpc-commands), and test_pi_platform_contract.py --pi-version ${{ matrix.pi-version }}.

The savings still hold. The heavy per-cell work #390 measured — six typechecks, six bundle builds, six 100-sample benchmarks, six copies of the static Python scripts, six release-package contracts — is gone. What returns to the matrix is Vitest time on an already-installed toolchain: 7 files, 159 tests, 4.7s locally. The pre-split worst cell (452s, windows-latest, run 30123976665) carried all of the removed work, so this job is a net reduction.

ca-pi-checks resolves its Pi version from the repo's own support policy (pi_promotion.py policy -> last_verified) rather than hardcoding it, so a Pi promotion — which rewrites the matrix via .github/pi-promotion-targets.json but would not know about a new hardcoded string — cannot leave this job pinned to a stale runtime.

The registration contract (called out as CRITICAL). ci-passed enforces a job through two independent registrations: the needs: list (makes the gate wait) and the required_results string (makes the gate care). ca-pi-checks is in both, and test_ci_impact.py now asserts they agree for every job:

self.assertEqual(sorted(set(needs) - set(required)), ["ca-pi-latest"])
self.assertEqual(sorted(set(required) - set(needs)), [])

The only sanctioned divergence is ca-pi-latest, the advisory WATCH canary. pi_ci_contract_violations() carries the same check independently.

Attestation and impact-map registration. Two follow-ons the first revision deferred are closed here, because both weaken something this lane created:

  • verify_pi_support.py::REQUIRED_HOSTED_CHECKS now names [CHECK] | [PI ] | Host-independent adapter contract directly. Reaching it only through Merge readiness meant a future edit to that gate's required_results could drop the verdict with no Pi-support evidence noticing.
  • .github/ci-impact-map.json gains the pi-checks id and adds it to the plugins/ca-pi/** edge, so a Pi payload edit predicts all three Pi contracts. pi-adapter's reproduce is corrected at the same time: the matrix no longer runs the whole suite, so the accurate local repro is python .github/scripts/test_pi_platform_contract.py --pi-version 0.80.10.

#399 — explicit job deadlines

How the values were chosen — from the two most recent hosted runs' Pi job durations (29870271440, 30123976665), not from guesses:

job observed timeout reasoning
ci.yml ca-pi-checks ubuntu cells 120/125/130/132s; plus full suite + benchmark, ~5 min expected 20 ~4x expected
ci.yml ca-pi-tools worst cell 452s (windows-latest, run 30123976665), and that cell also carried typecheck/build/benchmark/four Python scripts which have now moved out 25 ~3.3x the recorded worst case, room for a slow registry day
ci.yml ca-pi-latest 17-18s when the probe fails fast; a compatible latest runs the package suite + full platform contract 20 budgeted like the ubuntu adapter cell
ci.yml ca-pi-codeql 30 (pre-existing, unchanged)
ci.yml version-bump-pi 4-7s 10 bounds a wedged full-history git fetch
pi-promotion.yml resolve seconds 15 bounds a hung registry lookup
pi-promotion.yml validate heaviest Pi lane: two external Pi installs + rebuild + complete suite + platform contract on three OSes; ~15 min expected 45
pi-promotion.yml open-pr checkout + npm ci + rebuild + gh pr create 20

Every value is far below GitHub's 6-hour hosted job ceiling; the contract test asserts each Pi job declares a timeout and that it is 0 < t < 360.

#381 — the latest-Pi canary concludes advisory

ca-pi-latest was declared continue-on-error: true at job level. That keeps the workflow run from failing but GitHub still reports the check run with conclusion FAILURE — observed on PR #313 and on PR #420, where [WATCH] | [PI ] | Upstream compatibility <runtime: npm latest> was red while main was green.

The failing step on PR #420 (and on run 30123976665) is Report latest version and test installed runtime admission — the probe, not the harness:

{"name":"Install reviewed toolchain and external latest Pi (scripts disabled)","conclusion":"success"}
{"name":"Report latest version and test installed runtime admission","conclusion":"failure"}
{"name":"Run the latest Pi platform contract as a nonblocking canary","conclusion":"skipped"}

Now:

  • job-level continue-on-error is removed (it does not change the check conclusion, and it would mask real harness breaks);
  • the two upstream-compatibility probes carry step-level continue-on-error: true with ids admission and platform-contract;
  • a final if: always() step publishes an advisory receipt — the resolved latest version and each probe's outcome — to $GITHUB_STEP_SUMMARY, plus a ::warning annotation, and exits 0;
  • checkout / toolchain install / latest-Pi install / receipt publication are not absorbed, so a break in the canary harness still turns the check red (AC-2);
  • ca-pi-latest remains out of required_results (AC-3).

Would this have made PR #420's case advisory? Yes. Simulated with the exact step outcomes from that run:

$ GITHUB_STEP_SUMMARY=summary.md ADMISSION=failure PLATFORM_CONTRACT=skipped bash -eo pipefail receipt.sh
::warning title=Pi upstream compatibility::latest Pi (0.80.10) is outside the validated support window
(admission=failure, platform-contract=skipped). Advisory only - run the Pi promotion workflow to validate and promote it.
exit=0

Red-test evidence (verbatim, before any implementation)

First revision — the four issues

python -m unittest test_ci_impact.WorkflowContractTest run from .github/scripts/ against unmodified main:

AssertionError: Lists differ: ['activity.test.ts', 'background-jobs.test[330 chars].ts'] != []
First list contains 17 additional elements.
- ['activity.test.ts', 'background-jobs.test.ts', 'child-env.test.ts', 'compaction.test.ts',
-  'dispatch.test.ts', 'doctor.test.ts', 'farm.test.ts', 'final-arguments.test.ts',
-  'footer.test.ts', 'notices.test.ts', 'plan-mode.test.ts', 'policy.test.ts',
-  'process-tree.test.ts', 'runner-isolation.test.ts', 'runtime-resolver.test.ts',
-  'security.test.ts', 'windows-supervisor.test.ts'] : committed ca-pi test files that no required merge-gate job executes

AssertionError: 7 not greater than or equal to 8 : the Pi job scan found too few jobs
AssertionError: 'ca-pi-checks' not found in ['badge-consistency', 'ca-pi-codeql', 'ca-pi-latest', 'ca-pi-tools', ...]
AssertionError: <re.Match object; span=(158, 185), match='    continue-on-error: true'> is not None : job-level continue-on-error hides canary harness failures
AssertionError: [] == [] : no required ca-pi job runs the unfiltered `npm test` suite

Ran 9 tests in 0.005s
FAILED (failures=6)

test_pi_package.py::pi_ci_contract_violations also went red on the restructure and was updated in step, including three mutation assertions (a neutered full-suite run, a host-independent step creeping back into the matrix, and ca-pi-checks dropped from required_results while left in needs:).

Second revision — the coverage regression review found

New contracts written first, against the head commit 40f93d6 (the ubuntu-only partition):

FAIL: test_every_platform_gated_pi_test_file_runs_on_every_supported_os
AssertionError: Lists differ: ['activation.test.ts', 'background-jobs.te[121 chars].ts'] != []
First list contains 7 additional elements.
- ['activation.test.ts',
-  'background-jobs.test.ts',
-  'commands.test.ts',
-  'plan-mode.test.ts',
-  'runtime-resolver.test.ts',
-  'security.test.ts',
-  'windows-supervisor.test.ts'] : Pi test files that branch on the live platform but run on one OS only

FAIL: test_the_platform_gate_contract_binds_to_the_three_os_fan_out
AssertionError: Items in the second set but not the first:
'activation.test.ts'

FAIL: test_cli_writes_deterministic_json_and_a_markdown_summary
AssertionError: Lists differ: ['pi-adapter', 'pi-latest'] != ['pi-adapter', 'pi-checks', 'pi-latest']

FAIL: test_final_hosted_attestation_requires_repo_aggregate (test_verify_pi_support)
AssertionError: frozenset({'[CHECK] | [PI  ] | Adapter co[567 chars]t>'}) != {'[CHECK] | [PI  ] | Adapter contract  <o[612 chars]pt>'}

Each contract was then mutation-checked to prove it bites rather than merely passing:

# a future win32-gated test added to a file only the ubuntu lane runs
$ (append test.skipIf(process.platform !== "win32")(...) to policy.test.ts)
AssertionError: Lists differ: ['policy.test.ts'] != [] : Pi test files that branch on the live platform but run on one OS only
AssertionError: Lists differ: ['ca-pi-tools does not run platform-gated suite on every OS: policy.test.ts'] != []
   ^ both oracles fire independently

# a statically disabled test inside an "assigned" file
$ (change one `test(` to `test.skip(` in policy.test.ts)
AssertionError: {'policy.test.ts': ['test.skip']} != {} : ca-pi Vitest declarations disabled with no host predicate to satisfy

Plus, inside test_the_platform_gate_contract_binds_to_the_three_os_fan_out: collapsing os: [ubuntu-latest, windows-latest, macos-latest] to one runner must uncover every file, and deleting one filename from the matrix step must uncover exactly that file.


Verification

suite result
python -m unittest discover -s .github/scripts -p "test_*.py" 1046 tests, OK, 5 skipped
plugins/ca-pi/tools — full unfiltered npx vitest run (what ca-pi-checks runs) 23 files / 545 passed, 1 skipped
plugins/ca-pi/tools — the new matrix step's 7 platform-gated files, on Windows 7 files / 159 passed, 0 skipped

The 159-passed / 0 skipped line is the direct evidence the regression is repaired: on a Windows runner every one of those files' win32 branches executes. The 1 remaining skip in the full suite is process-tree.test.ts's POSIX-only case, which the matrix covers on its ubuntu and macOS cells.

The four test_pi_benchmark failures seen in a bare worktree were RuntimeError: Pi benchmark requires the installed pinned esbuild — no plugins/ca-pi/tools/node_modules. After npm ci --ignore-scripts they pass; nothing in this diff touches the benchmark.

Also re-run green (always-on CI jobs a workflow edit could affect):

python .github/scripts/check_docs_contract.py                          -> 0
python tools/build-surface.py --check                                  -> OK (claude, codex, pi in sync)
python .github/scripts/check_license_consistency.py .                  -> consistent
python tools/build-host-packages.py --check                            -> matches
python tools/build-host-packages.py --check --release-guard-base a3a2df2
    -> "Pi payload, version, changelog, and root metadata advanced together: 0.1.1 -> 0.1.2"
git diff --check                                                       -> clean; all changed blobs LF

Both workflows parse under yaml.safe_load; .github/ci-impact-map.json parses and validates through load_map.

Payload version

Commits 5ce9b5b and 40f93d6 touch plugins/ca-pi/** (the plan-mode.test.ts portability fix), so the Pi payload does require a bump. ca-pi is at 0.1.2 with a matching ## [0.1.2] CHANGELOG heading and the release guard confirms payload, version, changelog and root metadata advanced together. (An earlier version of this PR body claimed no bump was required, citing a guard run that predated those two commits — that claim was wrong and is retracted.)


Known limits (disclosed, not fixed)

  1. Bound Pi CI and promotion jobs with explicit job deadlines #399 AC-2 is structural only. Timeouts are declared and contract-tested (0 < t < 360 on all 8 Pi jobs) but no deliberately hanging fixture was run against a hosted runner to observe a job actually terminate at its bound and leave a useful receipt. Proving it costs a burned runner slot up to the declared deadline.
  2. Make the Pi latest-version canary conclude as advisory instead of failed #381 AC-2's "red harness" arm is asserted structurally, not observed live. The absorbed-probe path was exercised offline (bash -eo pipefail with ADMISSION=failure), and the harness steps are demonstrably un-absorbed, but a live red canary-harness run has not been produced. Note also that the always() receipt step wraps pi --version in || true and defaults to unresolved, so the "receipt publication failure -> red check" arm is effectively unfalsifiable as written.

Notes for later lanes rebasing onto this job graph

  • Job order in ci.yml is now ca-pi-checks -> ca-pi-tools -> ca-pi-latest -> ca-pi-codeql. ca-pi-tools appears as a new block in the diff even though the job id is unchanged; git renders the split as "rename the old block, add a new one".
  • Anything added to ci-passed.needs must also go into required_results, or test_ci_impact.py fails.
  • The matrix's platform-gated Vitest step is kept on one line on purpose: the .github/scripts workflow contracts are textual (stdlib-only, no YAML parser) and read the covered file set straight off a run: npm test -- ... line. A folded scalar (run: >-) would silently defeat them.
  • Adding a test.skipIf(process.platform ...) to a Pi suite now obliges that file to run in ca-pi-tools. Two independent contracts will tell you.

https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L

SUaDtL added 3 commits July 24, 2026 18:04
…, deadlines, advisory canary

Four CI-structure defects around the Pi jobs, fixed together because they all
reshape the same job graph in .github/workflows/ci.yml.

#405 - required PR CI named 6 of the 23 committed plugins/ca-pi/tools/test/
*.test.ts files, so policy, plan-mode, dispatch, background-jobs, activity,
doctor, footer, notices, runtime-resolver, and windows-supervisor could all
regress with every required check green. The new canonical Pi job runs an
UNFILTERED `npm test`, and test_ci_impact.py now computes the partition from
the workflow text and fails when any committed test file is unassigned to a
required shard.

#390 - the six-cell os x pi-version matrix re-ran package-metadata checking,
typecheck, the deterministic Vitest suites, the static security/parity scripts,
the bundle rebuild + staleness gate, the release package contract, and a
100-sample benchmark once per cell (1,423 runner-seconds on run 29870271440).
Those steps consume neither matrix.os nor matrix.pi-version, so they move to a
single canonical ca-pi-checks job; the matrix keeps only the installed-Pi
admission boundary, live package RPC activation, and the cross-platform
platform contract. ca-pi-checks is registered in BOTH ci-passed's `needs:` list
AND its `required_results` string, and a new contract test asserts the two
registrations agree for every job (only the advisory canary may diverge).

The canonical job resolves its Pi version from the repository's own support
policy rather than hardcoding it, so a Pi promotion cannot leave it pinned to a
stale runtime.

#399 - every Pi CI and promotion job now declares timeout-minutes derived from
recorded runtimes with bounded headroom, and a contract test rejects a future
Pi job that omits one.

#381 - the [WATCH] upstream-compatibility canary reported a FAILED check run
whenever upstream published a Pi outside the validated window (live on PR #420
while main was green). A job-level continue-on-error does not change the check
conclusion, so it is removed; the two upstream probes now absorb their own
failure at step level and an always-published receipt records the version and
each probe outcome in the job summary. A break in the canary HARNESS still
turns the check red.

Closes #405
Closes #390
Closes #399
Closes #381

Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L
The first required-CI run of the complete Pi Vitest suite (this PR's #405 fix)
immediately caught a defect the old 6-of-23 file filter had been hiding:
plan-mode.test.ts hardcodes "C:/repo" as the repositoryRoot argument to
operatePlanFile(). node:path isAbsolute() is platform-native, so that string is
absolute on Windows and RELATIVE on Linux and macOS - operatePlanFile() rejects
a non-absolute root and returns OPERATION_FAILED, so four of the canonical
plan-file bridge cases asserted nothing on the two hosts where they never ran.

Observed on run 30129967015, job "[CHECK] | [PI  ] | Host-independent adapter
contract" (ubuntu-latest):

  FAIL test/plan-mode.test.ts > canonical plan-file bridge operations
  AssertionError: expected { ok: false } to deeply equal { ok: true, ...(2) }
  Test Files  1 failed | 22 passed (23)
       Tests  4 failed | 535 passed | 7 skipped (546)

The fix is test-only: one REPOSITORY_ROOT constant picking a platform-absolute
spelling. Production plan-mode.ts is unchanged and was always correct.

Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L
The Pi release guard requires any plugins/ca-pi/** change to advance the
manifest version together with regenerated root metadata and a new exact
Keep-a-Changelog heading. The previous commit's test-portability fix touches
plugins/ca-pi/tools/test/, so 0.1.1 -> 0.1.2 (patch: test-only, no payload
behavior change).

ca-pi-v0.1.1 was never tagged, so the initial release version named in
docs/pi-parity-testing.md moves with it.

Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L
@SUaDtL

SUaDtL commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Hosted verification + two follow-on commits

CI is green on run 30130997652. Recording what the hosted runs actually proved, and the two commits added after the first push.

#405 immediately caught a real hidden defect

The very first hosted run of the unfiltered suite (30129967015, job [CHECK] | [PI ] | Host-independent adapter contract) went red:

FAIL  test/plan-mode.test.ts > canonical plan-file bridge operations
  > uses only slug+kind for read then CAS replace and returns committed bridge bytes
AssertionError: expected { ok: false } to deeply equal { ok: true, …(2) }

 Test Files  1 failed | 22 passed (23)
      Tests  4 failed | 535 passed | 7 skipped (546)

Root cause: plan-mode.test.ts passed "C:/repo" as repositoryRoot to operatePlanFile(), which rejects a root that is not isAbsolute(). node:path isAbsolute is platform-native — path.win32.isAbsolute("C:/repo") === true, path.posix.isAbsolute("C:/repo") === false — so on Linux and macOS all four canonical plan-file bridge cases silently took the OPERATION_FAILED path and asserted nothing. Because required CI only ever named 6 of 23 test files, nothing had run this file off Windows.

Fixed in fix(ca-pi): make plan-mode bridge tests portable off Windows — test-only, one REPOSITORY_ROOT constant. plugins/ca-pi/tools/src/plan-mode.ts is unchanged and was always correct.

This is exactly the class of regression #405 says the partial file filter was hiding, caught on the first run of the fix.

Payload version gate

Touching plugins/ca-pi/** (the test file) tripped the Pi release guard:

ca-pi version must strictly advance from 0.1.1 to a higher SemVer (got 0.1.1)

Note this guard is stricter than the ca / ca-sandbox ones — it fires on any plugins/ca-pi/** change regardless of whether the version is tagged. ca-pi-v* has no tags yet, so 0.1.1 was never released; bumped to 0.1.2 (patch, test-only) with regenerated root package.json, a new ## [0.1.2] - 2026-07-24 heading, and the <version> in docs/pi-parity-testing.md moved with it. Guard now:

Pi payload, version, changelog, and root metadata advanced together: 0.1.1 -> 0.1.2

#390 — measured runner-second reduction (AC-4)

baseline (run 30123976665, main) this PR (run 30130997652)
six matrix cells 130 + 125 + 194 + 196 + 452 + 415 = 1512s 75 + 75 + 119 + 146 + 352 + 365 = 1132s
canonical ca-pi-checks 66s
total Pi adapter runner-seconds 1512 1198
Windows critical path 452s 365s

-314 runner-seconds (-21%) with no loss of required verdict coverage, and ~90s off the Windows critical path. The remaining matrix cost is the cold npm install --global on Windows, which is inherently per-cell.

#381 — verified live

[WATCH] | [PI ] | Upstream compatibility <runtime: npm latest> concludes success on this PR, and every step including Publish the advisory upstream-compatibility receipt succeeded.

The exact failure this issue is about, from PR #420's canary (job 89598028781):

FAIL  test/package.test.ts > ca-pi package > installed Pi runtime is admitted by the production boundary
Error: codeArbiter requires Pi 0.80.5 or 0.80.10; install a supported Pi version and run /ca-doctor.

That is the probe step, not the harness — the toolchain and latest-Pi install both succeeded. Under this PR's structure that step carries continue-on-error: true, so the job proceeds to the receipt and concludes green with the incompatibility recorded in the summary.

Honest caveat: by the time this PR's run executed (~45 min later) pi@latest resolved to a version inside the validated window, so the failing probe path was not exercised live here. It is covered by (a) the step outcomes above from #420, and (b) a local execution of the extracted receipt script under bash -eo pipefail with ADMISSION=failure, which exits 0 and writes the advisory table.

#399 — deadlines observed in practice

All Pi jobs completed far inside their bounds on this run: ca-pi-checks 66s / 20 min, worst matrix cell 365s / 25 min, ca-pi-latest 30s / 20 min, version-bump-pi 11s / 10 min.

One flake seen and cleared

Run 30130392781's windows-latest · Pi 0.80.5 cell failed in process-tree.test.ts with Windows Job Object holder refused containment: ready-timeout after the test's own built-in retry. The windows-latest · Pi 0.80.10 cell passed in the same run with the same committed helper, and both Windows cells passed on the next run. Timing flake, not a consequence of this diff — but flagged here because it is the one place where behavior could plausibly have changed: the lean matrix no longer runs npm run build before the platform contract, so it now exercises the committed helpers/windows-supervisor.js rather than a freshly built one. ca-pi-checks' staleness gate proves those are byte-identical.

https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L

Review of the #390 split found a real, undisclosed Windows coverage
subtraction. Moving activation/commands/status/tool-guard into the single
ubuntu ca-pi-checks job pulled two genuinely host-DEPENDENT suites out of
required Windows CI:

  - activation.test.ts:388 `test.skipIf(process.platform !== "win32")`
    (fixed user-global update cache + symlinked-update-state rejection)
    now executed in NO required job on any platform.
  - commands.test.ts's four `symlink(..., win32 ? "junction" : "dir")`
    containment sites only ever exercised the POSIX "dir" branch, so the
    Windows junction escape vector lost its gate.

Re-audited the whole Vitest tree against an explicit rule instead of a
hand-kept list. A file is host-dependent exactly when it compares the LIVE
`process.platform` against a literal - either a `.skipIf`/`.runIf` gate that
skips the whole test off the wrong OS, or a ternary that selects a different
operating-system primitive. A platform value that is INJECTED
(`buildChildEnv({ platform: "win32" })`) or merely forwarded into a pure
function (`platform: process.platform`) does not qualify: child-env,
compaction, status and tool-guard run identical code on every host, so they
stay on the canonical lane. That partition yields 11 host-dependent files;
bridge/package/process-tree/runner-isolation already run per cell via
test_pi_platform_contract.py, and the other seven are restored to the matrix.
The host-independent savings #390 asked for are untouched - typecheck, the
bundle build, the benchmark and the Python scripts stay factored out, so the
matrix is still lighter than the 452s pre-split cell.

Also tightens the #405 partition contract, which was file-granular and blind
to a test's own gate - it reported activation.test.ts as "assigned" while the
ubuntu lane skipped its only win32 case. Two new invariants, each proven to
bite by mutation:

  - every file that branches on the live platform must run in a job that fans
    out over all three operating systems (asserted independently in
    test_ci_impact.py and in test_pi_package.py's pi_ci_contract_violations
    oracle, both deriving the set from the sources);
  - no committed Pi test may be disabled by a static `.skip`/`.todo`/`.only`,
    which is the other way a file stays "assigned" while contributing no
    verdict. A platform gate must be `.skipIf`/`.runIf` so the rule above can
    hold it.

Two gaps this lane's own NEEDS-TRIAGE had deferred are closed here, since
both weaken an attestation the lane created:

  - verify_pi_support.py REQUIRED_HOSTED_CHECKS now names
    "[CHECK] | [PI  ] | Host-independent adapter contract" directly instead of
    reaching it only through Merge readiness.
  - .github/ci-impact-map.json gains the `pi-checks` id, and `pi-adapter`'s
    reproduce command is corrected: the matrix no longer runs the whole suite,
    so the accurate local repro is test_pi_platform_contract.py.

Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L
@SUaDtL
SUaDtL merged commit 058f9c6 into main Jul 25, 2026
36 checks passed
SUaDtL added a commit that referenced this pull request Jul 25, 2026
Resolves three collisions with the work merged since a3a2df2:

- plugins/ca-pi/CHANGELOG.md — main shipped its own 0.1.2 (plan-mode test
  fix, #423). This branch's payload therefore advances to 0.1.3; main's
  0.1.2 section is preserved verbatim beneath it. plugins/ca-pi/package.json
  and the generated root package.json bumped together via
  tools/build-host-packages.py.
- .codearbiter/security-controls.md — kept this branch's ADR-0016/ADR-0017
  Pi boundary rows over main's superseded ADR-0014 rows, dropped this
  branch's `curl | bash` nixpacks row (main closed it under #401), and kept
  main's new "Closed exceptions" and "Container image inputs" sections
  verbatim. Line endings reconstructed against origin/main's exact per-line
  bytes, so the file stays 57/13 and `git diff --check` clean.
- .github/workflows/ci.yml — main's #423 added the contract that any Pi test
  file branching on the live platform must run in the three-OS fan-out.
  test/child-env.test.ts became platform-gated on this branch (its cleanup
  cases take a POSIX-only symlink path), so it joins that job's file list.
  Without it, test_ci_impact and test_pi_package both fail.

Verified on the merged tree: ca-pi 558 passed / 1 skipped, tsc clean;
.github/scripts 1064 OK / 5 skipped; payload gate 0.1.2 -> 0.1.3 advanced
together; live Pi 0.80.10 contract PASS; git diff --check clean.

Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant