Skip to content

feat(ci): the coverage union covers ca-pi/tools too (#537) - #545

Merged
SUaDtL merged 4 commits into
mainfrom
feat/537-ca-pi-coverage-union
Jul 29, 2026
Merged

feat(ci): the coverage union covers ca-pi/tools too (#537)#545
SUaDtL merged 4 commits into
mainfrom
feat/537-ca-pi-coverage-union

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Closes #537.

#521 shipped the rule and the union job for plugins/ca/tools. plugins/ca-pi/tools is the other platform-forked tree per tech-stack.md — Windows supervisor and process-tree paths — and was in scope for the rule with no job to compute it.

Why duplicated rather than a matrix over trees

Exactly the reason #521 recorded, restated here because it looks like avoidable duplication:

  • The audited-graph contract attributes a job's dependency graph by its working directory. A matrix.tree-templated one resolves to ., which nothing audits.
  • Compensating with extra npm audit steps breaks a second contract, which pins the exact audit inventory across ci.yml and docs.yml.

Both contracts are right, so it is one job per tree. ca-pi-checks audits this same literal directory under the identical path filter, which is what satisfies the first.

Advisory, on the same terms

Awaited by ci-passed so a hang stays visible, never in required_results, and both new jobs are added to the sanctioned-advisory assertion. DECISION-0031's Available reasoning applies unchanged.

A real defect caught while writing the contract

coverage-blob-ca-* also matches coverage-blob-ca-pi-ubuntu-latest.

On any PR touching both trees, the ca merge job would have downloaded Pi's blobs alongside its own and reported a cross-tree union under ca's name — silently, and with an entirely plausible number. Nothing would have looked wrong.

Each tree's artifacts now carry an -os- terminator (coverage-blob-ca-os-*, coverage-blob-ca-pi-os-*) so the globs are disjoint.

It is asserted by actually globbing each pattern against the other's real artifact names with fnmatch, rather than by eyeballing the strings — the contract fails if a merge job's pattern matches a foreign artifact, and if it ever stops matching its own:

mutant (colliding artifact globs): KILLED

Verification

test_ci_impact.py 53 pass. ci.yml parses. tech-stack.md's per-tree table now says ubuntu+windows for ca-pi instead of "not yet", and documents the namespacing and why it exists.

The union figures themselves will appear on this PR's own run — ca-pi is touched, so its cells execute here.

SUaDtL added 2 commits July 29, 2026 10:15
#521 shipped the rule and the union job for plugins/ca/tools. ca-pi/tools is the
other platform-forked tree per tech-stack.md - Windows supervisor and
process-tree paths - and was in scope for the RULE with no job to compute it.

Mechanical duplication rather than a matrix over trees, for the reason #521
recorded: the audited-graph contract attributes a job's dependency graph BY its
working directory, and a templated one resolves to `.`, which nothing audits.
Compensating with extra `npm audit` steps breaks the contract pinning the exact
audit inventory across ci.yml and docs.yml. Both contracts are right, so one job
per tree it is. `ca-pi-checks` audits this same literal directory under the
identical path filter.

Advisory on the same terms: awaited by ci-passed so a hang stays visible, never
in required_results, and both new jobs are named in the sanctioned-advisory
assertion.

A REAL defect caught while writing the contract: `coverage-blob-ca-*` also
matches `coverage-blob-ca-pi-ubuntu-latest`. On any PR touching both trees the
ca merge job would have absorbed Pi's blobs and reported a cross-tree union
under ca's name - silently, and with an entirely plausible number. Each tree's
artifacts now carry an `-os-` terminator so the globs are disjoint.

That is asserted by actually globbing each pattern against the other's real
artifact names with fnmatch, not by eyeballing strings: the contract fails if a
merge job's pattern matches a foreign artifact, AND if it stops matching its own.
Verified load-bearing - restoring the colliding names turns test_ci_impact red.

Claude-Session: https://claude.ai/code/session_01WJgVfZw7J81PB7mwpHyUxx
The first run failed 20 tests in runner-isolation.test.ts on both hosts. Not a
flake and not a config slip: ca-pi's suite is NOT runnable without an installed
Pi host, and `npm run coverage` - the command tech-stack.md names for this tree -
runs the WHOLE suite.

It passes locally only because a Pi runtime happens to be on this machine's PATH;
on a bare runner those tests fail rather than skip. Verified both directions.

The cells now install the host the same way `ca-pi-tools` does, on node 22.19.0
(ca-pi's engines require it, and measuring on a different runtime would measure a
different code path), with Python present for the bridge.

ONE Pi version rather than that job's {0.80.5, 0.80.10} matrix: this measures
which LINES execute, which does not vary by host version in any way a second cell
would reveal. Pinned to the upper bound of the supported window.

Timeouts raised to 25 minutes to match ca-pi-tools, whose 452s worst cell is
dominated by the same cold Windows global install these now pay.

Claude-Session: https://claude.ai/code/session_01WJgVfZw7J81PB7mwpHyUxx
SUaDtL added 2 commits July 29, 2026 10:46
)

The Pi union cell's remaining Windows failure, and the THIRD instance this
session of one root cause: a Windows 8.3 short name compared against its long
form.

canonicalPath resolves with `realpathSync.native`, which expands 8.3 names. The
test built both its fixture root and its expectation with plain `realpathSync`,
which resolves symlinks but does NOT expand them. On a GitHub runner, where
tmpdir() is the RUNNER~1 form, the subject correctly returned the long path and
the test demanded the short one:

  expected 'C:\Users\runneradmin\AppData\Local\Te...'
        to be 'C:\Users\RUNNER~1\AppData\Local\Temp\...'

The implementation was right; the fixture was wrong. Both sites now use
`.native`, matching the contract under test - the fixture root especially, since
a non-native root hands every case in the file a path the implementation will
legitimately disagree with.

Invisible on any developer box whose profile path is already 8.3-clean, which is
why it took a second host to find - the same reason #539 and #541 hid.

751 ca-pi tests pass. Test-only: ca-pi ships from extensions/, not tools/, so
this is no payload change and needs no version bump.

Claude-Session: https://claude.ai/code/session_01WJgVfZw7J81PB7mwpHyUxx
@SUaDtL
SUaDtL merged commit 1eb691c into main Jul 29, 2026
46 checks passed
@SUaDtL
SUaDtL deleted the feat/537-ca-pi-coverage-union branch July 29, 2026 15:03
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.

coverage union: add the ca-pi/tools host cell (#521 follow-up)

1 participant