Skip to content

Commit e5705a8

Browse files
huangyiireneclaude
andauthored
ci(temporal-conformance): hand the runtime cascade-delete matrix a live PostgreSQL URL (#18772)
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 #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](https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent be7763a commit e5705a8

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,56 @@ jobs:
14441444
run: |
14451445
pnpm --filter @objectstack/metadata-protocol exec vitest run live-mysql live-postgres
14461446
1447+
# ── The cascade-delete multi-value lookup pin, on the live PostgreSQL ──
1448+
#
1449+
# `packages/runtime` rides this job for the same reason metadata-protocol
1450+
# above does: this is where a live PostgreSQL already exists. Only the
1451+
# matrix file runs here — the rest of that package's suite has no server
1452+
# axis and runs in Test Core.
1453+
#
1454+
# WHY (#18734). #18172 was a p1 that reached TWO published releases and
1455+
# was found by a customer rather than by CI: every DELETE of an object
1456+
# targeted by a `multiple: true` reference answered 500 on PostgreSQL,
1457+
# always, while the only real-stack pin of that path stayed green
1458+
# throughout — because it hard-coded `client: 'better-sqlite3'`. #18732
1459+
# removed that literal and gave the file a driver axis, and SHOWED the
1460+
# live cell red: ablating `SqlDriver.applyJsonMembership` produced
1461+
# `6 failed | 9 passed`, all six failures in the live cell and ZERO in
1462+
# SQLite, reproducing `operator does not exist: json ~~ text` (42883).
1463+
#
1464+
# ⚠ "There is a pin that can go red" and "that pin will be run" are two
1465+
# different claims, and until these two steps only the first was true.
1466+
# Measured on `origin/main` before this landed: `@objectstack/runtime`
1467+
# occurred ZERO times in this job's window, against a firing control of
1468+
# SEVEN for `driver-sql`. Without a URL the cell is a NAMED SKIP that
1469+
# says which variable would run it — a report, NOT coverage, and the
1470+
# shape that reads as "already fixed" in every review.
1471+
#
1472+
# `OS_EXPECT_LIVE_DIALECT_MATRIX` is scoped to the STEP, like the two
1473+
# legs above and deliberately not to the job: it asserts "the runner
1474+
# provisioned what THIS step needs", so it stays honest if a later step's
1475+
# server is ever dropped. No stall guard, matching the metadata-protocol
1476+
# leg — the two legs that carry one are the two that actually hit #4331.
1477+
#
1478+
# ⛔ THE POSITIONAL IS A SUBSTRING, NOT A GLOB — the same reading the
1479+
# metadata-protocol step records above, where the glob form matched zero
1480+
# files. ⛔ Do NOT "improve" it into `src/cascade-delete-*.test.ts`: that
1481+
# selects nothing, and a test that cannot fail reports success, which is
1482+
# the exact defect class this step exists to close. (`packages/runtime`'s
1483+
# vitest config also runs `runFilterPreflight` (#17853/#17978), which
1484+
# speaks up when a named path selects no tests — a second net, not a
1485+
# licence to change the form.)
1486+
- name: Build runtime and its dependencies
1487+
run: pnpm exec turbo run build --filter=@objectstack/runtime... --concurrency=4
1488+
1489+
- name: Run the runtime cascade-delete matrix against live PostgreSQL
1490+
env:
1491+
OS_TEST_POSTGRES_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres
1492+
OS_EXPECT_LIVE_DIALECT_MATRIX: '1'
1493+
run: |
1494+
pnpm --filter @objectstack/runtime exec vitest run --project local \
1495+
cascade-delete-multivalue-lookup-real-driver
1496+
14471497
dogfood:
14481498
# Sharded 3-way: the suite is ~60 independent test files, each booting its
14491499
# own in-process app; a single 4-vCPU runner needed ~7½ minutes for the

0 commit comments

Comments
 (0)