Repository navigation
ci: scope each binding's e2e freshness to its own package config - #971
Merged
Merged
Conversation
`[e2e].extra_scope` covered the shared Rust core but neither binding crate, so `packages/python/src` (PyO3) and `packages/ts/napi` were outside every package's e2e scope: a binding-only diff left that SDK's attestation looking fresh. The `extra_scope` comment justified this with the spawn model -- the packages ship a `dirsql` binary their e2e suites spawn, so only the core matters. Since #721 that is false: each launcher calls the core's `run_cli` in-process through its binding, and each binding's `run_cli` does argv framing plus GIL detach (PyO3) / exit-code handling (napi). That code runs in every e2e case and can change what the suites exercise with no core change at all. `[e2e]` is one global table applied to every caller reading a given config, so "core + my own binding" is only expressible per package. `packages/python` and `packages/ts` therefore get their own `testing-conventions.toml`, passed explicitly as each lane's `config:` -- the pattern `internals/checks` established in #550 to drop a phantom root, used here to add a real one. Declaring both bindings at the repo root instead would make a napi change demand a python re-attest, and would need `packages/ts/napi/**` in the python lane's path triggers to enforce even that. The root `[e2e]` block stays as the default for a caller with no config of its own; its stale spawn-model wording is corrected. Proven with upstream's detect.py at the pinned v0 sha (79fd4b6183dfd2ff276a8d55b973d7a182fc75e4) and real `e2e verify` runs over synthetic single-root diffs -- see the PR body's truth table. Fixes #933 skip-changelog: CI gate configuration and agent docs only; no runtime, API, or packaged-artifact change in either SDK.
The two new package configs carried 34 comment lines each for two lines of config -- twice the most verbose precedent (internals/checks, 16) -- and most of it restated the PR body and agents/reference/e2e-attestation.md rather than a constraint a reader could not see. The #721 narrative, the Cargo.toml boundary note and the cross-lane fan-in argument live in the reference doc; what stays is the part that keeps someone from folding `[e2e]` back into the root file. Rendered flags and gates unchanged: detect.py still emits the same --extra-scope pair for both lanes, preflight still passes. skip-changelog: comment-only edit to CI gate configuration.
thekevinscott
enabled auto-merge
August 20, 2026 17:56
This was referenced Aug 20, 2026
Closed
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #933
The decision: Option A, and Option B is dead
Option B's premise — the binding cannot change e2e behavior without the core also changing — is false. Since #721 each launcher calls the core's
run_cliin-process through its binding, and each binding's ownrun_clidoes real work that runs in every e2e case:packages/python/src/lib.rs:462— argv framing +py.detach(releases the GIL for the CLI's lifetime)packages/ts/napi/src/lib.rs:51— argv framing + the return-rather-than-exit contract (721/1 — Relocate CLImain+ clap structs intosrc/cli/; bin becomes a thin shim overrun_cli(argv)#737)A change to either alters what the e2e suites exercise with no core change at all. So the scope widens.
Why per-package config files rather than one root list
[e2e]is a single global table that upstream'sdetect.pyapplies to every caller reading a given config, so "the core + my binding" is not expressible in one shared file. Declaring both bindings at the repo root would:packages/ts/napichange demand a python re-attest (the issue explicitly rules this out — a napi change has no bearing on the python suite), andpackages/ts/napi/**in the python lane's path triggers to enforce even that — otherwise the demand is latent and fires only on PRs that happen to touch both. That is exactly the cross-lane fan-in Epic — CI: run only the checks relevant to the changed paths #834 removed.So
packages/pythonandpackages/tseach get their owntesting-conventions.toml, passed explicitly as that lane'sconfig:. This is the patterninternals/checksestablished in #550 and the embeddings plugin follows — there to drop a phantom root, here to add a real one.A dedicated
e2e-verify-only job per binding was considered and rejected: it cannot work for TypeScript.packages/ts/napicarries its ownCargo.toml, soderive_package_rootresolves topackages/ts/napi, which holds no receipts — verified, the gate reportse2e_attestation falseand skips itself.Changes
packages/python/testing-conventions.tomlextra_scope = ["packages/rust/src", "packages/python/src"]+ the same[python.coverage]floorpackages/ts/testing-conventions.tomlextra_scope = ["packages/rust/src", "packages/ts/napi"]+ the same[typescript.coverage]floors.github/workflows/dirsql-{python,typescript}-ci.ymlconfig: packages/<pkg>/testing-conventions.toml; the roottesting-conventions.tomlpath trigger is dropped (no job in either lane reads it now)testing-conventions.toml[e2e]comment's stale spawn-model premise corrected (#721); the block documented as the default for a config-less caller; header refreshed (it still named the pre-#834conventions.yml/python-test.yml)AGENTS.md,agents/reference/e2e-attestation.md,agents/reference/testing-gates.md,agents/environments/remote.md--confignow points at the package file, matching CIThe
config:is passed explicitly on purpose:derive_configtreats the literal default stringtesting-conventions.tomlas a request for package-root discovery, so these files would have been picked up silently. Explicit paths make the YAML state what CI reads and keeppreflight'sread_e2e(root.config)in agreement with it.Deliberate boundary, documented in both new files:
packages/python/Cargo.toml(the PyO3 crate manifest) is not scoped —extra_scopetakes directories, and the only directory holding it is the package root, where scoping would re-stale on the docs/tests/pyproject edits the--scopenarrowing exists to ignore. The napi entry is the whole crate dir, so its manifest andbuild.rsare covered.Verification
Upstream read at the pinned
v0sha79fd4b6183dfd2ff276a8d55b973d7a182fc75e4, per the "read upstream at a pinned sha, trustMIGRATIONS.mdover probing" rule.RED → GREEN, from real
uvx testing-conventions e2e verifyruns over synthetic single-root diffs (--base main, no receipt in the diff):packages/python/srconlypackages/ts/napionlyReproduce:
Manual exercise of the wiring — upstream's own
detect.pyrun against this checkout, which is what renders the flags thee2e-verifystep appends:Also green locally:
dirsql-checks preflight --conventions .github/workflows/dirsql-{python,typescript}-ci.yml --gate colocated-test --gate unit-lint --gate integration-lint— 0 failing pairs on both lanes, including the two rust binding-crate jobs now reading the package config ([rust].featuresis consumed only by coverage/mutation, neither of which those jobs run).changelog-gatepasses on theskip-changelogline. Both lanes'e2e verifyover this branch's diff exit 0 — this PR touches no scoped source, so it needs no re-attestation.E2E Verification
N/A - CI gate config + agent docs only (no
packages/*/src, no SDK runtime code)packages/python/e2e-attestation.jsonrefreshed ifpackages/pythonchanged — not required: the change is outside--scope packages/python/dirsqland outside both extra scopes (verified, exit 0)packages/ts/e2e-attestation.jsonrefreshed ifpackages/tschanged — not required, same (verified, exit 0)uvx testing-conventions e2e verify packages/{python,ts} --scope <src> --base main <extra-scope flags>Changelog / Migrations
packages/<pkg>/changelog.d/for each changed package — not applicable:skip-changelog:line on the commit, reason "CI gate configuration and agent docs only; no runtime, API, or packaged-artifact change in either SDK." Verified accepted bydirsql-checks changelog-gatelocally.packages/<pkg>/migrations.d/— not required: no public API or runtime behavior change.PARITY.mduntouched — no SDK public API is affected.Noticed, not fixed here
just preflightis broken onmain:preflight/cli.pystill defaults--conventionsto.github/workflows/conventions.yml, which the #834 split removed, so it only runs when given an explicit--conventions <file>(one lane at a time — that is how it was run above). Worth its own issue rather than widening this PR.Generated by Claude Code