Skip to content

ci(temporal-conformance): hand the runtime cascade-delete matrix a live PostgreSQL URL - #18772

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-18734-runtime-live-pg-ci-leg
Sep 17, 2026
Merged

huangyiirene merged 1 commit into
mainfrom
claude/issue-18734-runtime-live-pg-ci-leg

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #18734

Clause-②: no

What moved

Two steps into Temporal Conformance (live PG + MySQL), the job that already provisions a health-checked PostgreSQL 16 and already runs driver-sql, the non-SQL temporal backends and metadata-protocol against it.

PR #18732 gave packages/runtime/src/cascade-delete-multivalue-lookup-real-driver.integration.test.ts a live PostgreSQL cell and showed it red before allowing it green (ablation of SqlDriver.applyJsonMembership: 6 failed | 9 passed, all six in the live cell, zero in SQLite, reproducing operator does not exist: json ~~ text / 42883 byte for byte). Nothing in CI handed that cell a URL, so it reported itself un-run on every job. "There is a pin that can go red" and "that pin will be run" are two different claims, and only the first was true.

The two steps are byte-identical to the derivation in PR #18732's body — same md5 over the ten lines, not retyped from memory and not re-derived here. The only thing this PR adds around them is the comment block that records why they exist and what must not be done to them.

The positional is a SUBSTRING, not a glob — measured on THIS file

The card and #18732 both carry this reading from metadata-protocol. It was re-measured here, on the file this step actually selects, rather than carried over:

form reading
cascade-delete-multivalue-lookup-real-driver (the substring, as shipped) 1 test file selected — Test Files 1 passed (1), Tests 7 passed | 1 skipped (8)
src/cascade-delete-*.integration.test.ts (the "improvement") No test files found, exiting with code 1

⇒ The step runs tests, stated as a count and not an exit code: 8 tests across 1 file, 7 of them the SQLite cell and 1 the live cell naming itself as un-provisioned. On CI, where the URL is supplied, that cell expands to the 8 live tests #18732 measured, for 15 total.

packages/runtime's vitest config also runs runFilterPreflight (#17853/#17978), which speaks up when a named path selects nothing — a second net, and the comment says explicitly that it is not a licence to change the form.

Both env lines are load-bearing — positive control

OS_EXPECT_LIVE_DIALECT_MATRIX: '1' with the URL withheld:

FAIL |local| ... (live postgres) > is provisioned — set OS_TEST_POSTGRES_URL to run this cell
AssertionError: OS_TEST_POSTGRES_URL is unset while OS_EXPECT_LIVE_DIALECT_MATRIX=1: this
runner declared it provisions a live server, so the live postgres cell ... must not be skipped.
Tests  1 failed | 7 passed (8)

⇒ If the URL line is ever dropped while the flag stays, this step reds instead of quietly degrading to SQLite-only coverage. That is the same vacuous-pass guard the driver-sql and metadata-protocol legs above already carry, and it is scoped to the STEP rather than the job for the same reason theirs is: it asserts "the runner provisioned what THIS step needs", so it stays honest if a later step's server is ever dropped. The card listed the step-versus-job question as Not measured; this is the answer and the reason.

Job wall-clock — the cost on every PR, priced

The seat asked to hear this plainly rather than discover it later. It is not four minutes.

reading value
the job today, run 35263914432 (95b21b33b) 345s (5.8 min)
the job today, run 35262334045 (09e16a574, colder cache) 432s (7.2 min)
its timeout-minutes 30
build tasks in @objectstack/runtime... 31
build tasks the job's three existing legs already cover 18
⇒ packages this build step newly adds 13
the new build step, warm Turbo cache 71ms — FULL TURBO, 30/30 cached
the new build step, fully cold on this container 4m20s for all 30 tasks (only 1 cached)
the new test step, SQLite-only shape 8.00s

The warm figure is the common path, and it is what CI actually shows: in run 35263914432 all three existing build steps took 0–1s, because this job restores the Turbo cache from the Build Core namespace, which builds every package. The cold figure bounds the other end — and note the 4m20s is for the whole 30-task closure, of which 18 tasks are ones the job already pays for today; the marginal 13 sit inside the band CI's own colder run shows for the sibling steps (driver-sql's closure 106s, the non-SQL one 42s).

⇒ Honest estimate: a few seconds on the common path, roughly 1–2 minutes when the Turbo cache misses, against a job that runs 5.8–7.2 min with about 23 minutes of headroom under its own timeout. No job name and no matrix shape changed, so the merge-queue required set is untouched (check:required-contexts green).

Scope and grading

  • Clause-②: no — measured, not assumed. The diff is one file. Predicate: is a changed path inside any workspace package's shipping set (package dir joined with each entry of its files[], private packages excluded)? Enumerated 217 shipping roots across the workspace; .github/workflows/ci.yml is inside 0 of them. Positive control on the same predicate: packages/adapters/hono/dist/index.js resolves to 1 package (@objectstack/hono). No accept set moves, no schema, no exported symbol, no door.
  • skip-changeset — same measurement, and it is also this workflow's own prescription: pr-automation.yml lists .github/ under "It releases nothing ... apply the skip-changeset label. PREFERRED".
  • Not a governed surface: scripts/pm/check-governed-merges.mjs --test .github/workflows/ci.yml exits 0, 0 of 1 path hits the register.
  • needs:contract-review is the seat's label; this PR neither hangs nor removes it.

Verification

Base 95b21b33be; final commit measured below. Heavy runs through scripts/pm/os-verify-lock.sh.

what reading
derived gate families (scripts/pm/dispatch-gates.mjs --repo ... --ran) 44 derived, 44 accounted — 42 green, 2 NOT MEASURED
— of those, the workflow-reading ones check:ci-filter-parity, check:required-contexts, check:workflow-step-name-quoting, check:workflow-status-functions, check:step-collectors, check:self-test-workflow-commands, check:stall-guard-budget, check:stall-guard-headroom, check:pnpm-filter-targets — all green
pnpm check:nul-bytes green (8835 files); plus a direct control-byte scan of the diff — 0 hits
workflow parses yaml.parse — steps land in job temporal-conformance, 16 steps, env and run bodies as intended
the two steps vs PR #18732's derivation md5 identical (26e85b39...)
eslint the changed file is outside eslint's population — isPathIgnored('.github/workflows/ci.yml') = true, 1 result object with 0 errors (the ignored-file warning); positive control eslint.config.mjs returns isPathIgnored = false. eslint.config.mjs is not in this diff, so no untouched file's verdict can move. The repo-wide scan is CI's run, not one this PR narrows away from.

The 2 NOT MEASURED, named:

  • pnpm check:dual-build-cjs-loads — exit 3, PREREQUISITE NOT MET: it reads built output for ~30 packages this worktree never built and says so itself ("This is NOT a pass: nothing was measured"). CI builds the repo and measures it there.
  • pnpm check:pm-dispatch-gates — exit 124, killed by this container's foreground wall at 540s. Not a refusal and not a red: 1768 self-test assertions printed green and zero failed before the kill. CI measures it.

Acceptance notes

  • ⚠️ A stray remote branch this round created and could not delete: claude/issue-18734-workflow-scope-probe (commit f22c6321, a throwaway comment appended to ci.yml, no PR). The dispatch required proving a .github/workflows/** push is accepted before spending the round, and it is — but deleting the probe afterwards is blocked on both channels: git push origin --delete returns RPC failed; HTTP 403 from the egress proxy, and DELETE /repos/.../git/refs/heads/... returns 403 {"message":"Write access to this GitHub API path is not permitted through this proxy."}. It needs a hand with delete rights. The lesson is cheap and worth writing down: probe on the branch you are going to keep, because a probe branch is easier to create than to remove here.
  • The 29 other better-sqlite3 literals under packages/runtime/src/ — noted, not filed, unchanged from test(runtime): pin the multi-value cascade-delete path on PostgreSQL, not only SQLite #18732's reading: none carries a shipped dialect-specific defect, and this card explicitly does not reopen that. Carrier: whichever card next names a dialect-specific defect on one of those paths.
  • Nothing here repairs anything the newly-powered cell may turn red. If it goes red on this PR's own CI run, that is a finding for the seat, not a repair to smuggle into a workflow PR.

Generated by Claude Code

…ve PostgreSQL URL

The `Temporal Conformance (live PG + MySQL)` job already provisions a
health-checked PostgreSQL 16 and runs driver-sql, the non-SQL temporal
backends and metadata-protocol against it. It does not run
`@objectstack/runtime` at all — measured zero occurrences in the job
window against a firing control of seven for `driver-sql` — so the live
PostgreSQL cell that landed on
`cascade-delete-multivalue-lookup-real-driver.integration.test.ts` reports
itself un-run on every job.

That cell is red-capable and was shown red before it was allowed to be
green. What was missing is only provisioning: two steps in the job that
already has the server, taken verbatim from the derivation in the PR that
built the cell.

The positional is a SUBSTRING filter, not a shell glob. The glob form
matches zero files, and a step that selects nothing reports success.

Claude-Session: https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant