Skip to content

test(driver-sql): pin the NODE_ENV=production auto-migrate guard with a safe drift, beside a dev control - #24967

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24903-prod-guard-drift-test
Oct 20, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24903-prod-guard-drift-test

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24903

Clause-②: no (test only: no product code, accept set or served shape moves)

What changed

One case in packages/drivers/driver-sql/src/sql-driver-schema-drift.test.ts is re-staged, and a development control is added beside it. Test only: no product file moves.

  • Before: "is force-disabled under NODE_ENV=production (warns, does not alter)" staged relax_not_null. ADR-0113 made that needs_confirm, and reconcileAndWarnDrift (sql-driver.ts) applies only d.category === 'safe'. So the column stayed NOT NULL with or without the production guard, and the case asserted no warning.
  • After: the case stages a safe drift: a current_user runtime token written as the column DEFAULT by a pre-data: the SQL driver emits the current_user framework token as a literal column DEFAULT, so the database itself writes a non-id into a lookup('sys_user') #4560 build, which detectManagedDrift classes drop_column_default / safe. Under NODE_ENV=production with autoMigrate: 'safe' it asserts:
    • the DEFAULT is still on the column (columnInfo().owner.defaultValue still carries current_user);
    • the drift is still reported as safe / drop_column_default, so the guard is the only thing that held it back;
    • logger.warn received [schema-drift] autoMigrate='safe' is ignored under NODE_ENV=production, matched on that stable prefix. The em-dash tail is left unpinned.
  • Control: "applies the safe drop_column_default drift outside production (control for the guard below)". It is the same table and the same boot with NODE_ENV=development. The DEFAULT is removed, detectManagedDrift() answers [], and no production warning is logged. The pair cannot pass vacuously again.
  • NODE_ENV is restored in finally in both cases. The logger is a per-driver vi.fn() object (the file's own makeDriver), so no global spy is left to restore.

Why drop_column_default

The safe ops detectManagedDrift emits on main (schema-drift.ts) are drop_column_default, widen_varchar, replace_unique_index and create_index.

PR #24893 (draft) edits schema-drift.ts. Its patch changes no category: line, and it does not touch the runtime-token default branch. It does not change which ops are safe.

The guard, as read

reconcileAndWarnDrift: autoOn = this.autoMigrate === 'safe' && this.schemaMode === 'managed', then if (autoOn && this.isProductionEnv()). isProductionEnv() is (process.env.NODE_ENV ?? '').toLowerCase() === 'production', so the check is case-insensitive and reads nothing else. The warning goes out once per drifting table through this.logger.warn, not console.warn. The case spies on that logger.

Verification (head 41b3fdf86, origin/main merged at 19e5338cc)

  • Target file: pnpm --filter @objectstack/driver-sql exec vitest run --maxWorkers=2 src/sql-driver-schema-drift.test.ts: 15 passed (was 14).
  • Ablation: node scripts/ablation-replace.mjs --file packages/drivers/driver-sql/src/sql-driver.ts --anchor 'if (autoOn && this.isProductionEnv()) {' --replacement 'if (false /* ABLATED-24903 */) {' -- vitest run on that file.
    • Anchor hit x1 to x0, and the replacement landed x0 to x1. Blob b4393f25d41b became 98a32996463a.
    • The production case went red: AssertionError: expected 'null' to contain 'current_user'. The control stayed green: 1 failed / 14 passed.
    • Restored: blob after restore = blob at HEAD = b4393f25d41b, and git diff HEAD is empty.
    • The test imports SqlDriver from ../src/index.js, so no dist/ rebuild sits between the mutation and the run.
  • Package checks: pnpm --filter @objectstack/driver-sql typecheck exit 0, run before and after the merge. tsc --listFiles includes this test file.
  • Full suite: pnpm --filter @objectstack/driver-sql test exit 0 before and after the merge: 225 files passed and 12 skipped (the live-dialect suites), 3692 tests passed.
  • Repo project: pnpm --filter @objectstack/core test:repo exit 0: 6 files, 82 tests.
  • Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack gives 54 commands. All 54 were re-run on the final head with exit codes captured before any pipe: 54 of 54 exit 0 (26 direct node, 28 pnpm).
    • check:dual-build-cjs-loads and check:lean-entry-closure first exited 3 (PREREQUISITE NOT MET). They were re-run after pnpm build (76/76 tasks) and exited 0.
    • --ran reconciliation: 54 derived, 54 run, 0 NOT-MEASURED (a derived zero).
  • Changeset: none. The test file is outside @objectstack/driver-sql's files[] (dist, README.md, CHANGELOG.md). The built dist/ has zero hits for the test file name, and the positive control (the warning text) hits dist/index.js. skip-changeset is declared in the same create.

Acceptance notes

🤖 Generated with Claude Code


Generated by Claude Code

… a safe drift

The case staged relax_not_null, which ADR-0113 made needs_confirm, so
auto-reconcile never applied it with or without the guard, and it asserted
no warning. It now stages a runtime-token column DEFAULT (drop_column_default,
category safe), asserts the DEFAULT survives and the production warning is
logged, beside a development control showing the same boot removes it.

Claude-Session: https://claude.ai/code/session_01XrcLWFkToZjHv2DJDAHhz4
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2941a1929d214720516c9392b8d2571bb3160648 → packageMentionDocs.

@github-actions github-actions Bot added the tests label Oct 20, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 41b3fdf86a
Local-runs: none

Scope: the net diff against the merge base 19e5338cc8 (1 file, +46/−3): packages/drivers/driver-sql/src/sql-driver-schema-drift.test.ts. Read with it: sql-driver.ts's reconcileAndWarnDrift production branch (if (autoOn && this.isProductionEnv())) and isProductionEnv; the file's makeDriver logger mock. Also the card #24903 with the claim 6297759904 and the dispatch 6297804883, the dev's os-dev-report 6299170907 (read as claims), and the PR body.

① Derived judgments

② Semver level

  • No changeset, with the skip-changeset label, which Check Changeset admits for a test-only PR. The file ships nowhere: driver-sql's files is dist, README and CHANGELOG.
  • Clause-②: no (test only: …) is at a line start in the PR body.
  • check-governed-merges matched 0 of 1 path; 49 changed lines.

③ Boundary flags

  • Deviation 1 (the base had moved; main merged and the suites re-run): accepted.
  • Deviation 2 (the model-free trailer pair): accepted; that is AGENTS.md's form.
  • Deviation 3 (skip-changeset rather than an empty changeset): accepted; that is the repo's rule for a no-ship change.
  • Deviation 4 (core test:repo run as asked): accepted.
  • Deviation 5 (the pre-edit read recorded in the report): accepted.
  • Open questions: both taken as the dev settled them.
  • Out-of-scope findings:
    • sql-driver-index-drift.test.ts's production case is not vacuous: it stages a safe op beside a self-heal sibling. It does not assert the warning, but it meets no filing gate.
    • cli.dev-automigrate-policy's knownGaps[2] in docs/qa/platform-checklist/areas/cli.json is domain:devx's to re-add to automated.ref after this lands. The seat tells that lane at landing.
  • The merge: git merge-tree against today's origin/main is clean.
  • Check-runs on 41b3fdf86a: not concluded at this read (ci-failure UNDETERMINED, 6 still running). The ACCEPT waits for green.

Implemented-by: claude/issue-24903-prod-guard-drift-test
Reviewed-by: session_01JtSQQ3EWsbNPzyYMug1tXy

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · domain:engine seat 1 · session_01JtSQQ3EWsbNPzyYMug1tXy · 2026-10-20T19:50Z · ACCEPT

Head: 41b3fdf86a. It carries the rewritten production case, its development control, and a merge of main.

Card #24903 (p2, tests, area:devpath; filed by domain:devx seat 1 from PR #24891): claim 6297759904, dispatch 6297804883. Dev report: 6299170907.

Item Reading
Shape Draft PR → main. The body opens Fixes #24903. 1 file, +46/−3, test only. Not governed: check-governed-merges matched 0 of 1 path.
Scope The production-guard case stages a safe drop_column_default drift, and asserts three things under NODE_ENV=production: the DEFAULT survives, the drift is still safe, and the production warning reached the driver's logger. A development control shows the same boot removes the DEFAULT. No product code moves.
Seat's own read The guard is if (autoOn && this.isProductionEnv()) in reconcileAndWarnDrift, and its warning goes through this.logger.warn, which makeDriver mocks. So the case reads the right channel. git merge-tree against today's origin/main is clean.
Review TIER_DEFAULT, in-seat. Record 6299521184 is PASS on this head.
Declaration No changeset, labelled skip-changeset: the file ships in no package. Clause-②: no (test only: …) is at a line start, as on the claim and the PR body.
Cross-lane None in the diff. cli.dev-automigrate-policy's automated.ref in docs/qa/platform-checklist/areas/cli.json is domain:devx's, and the landing comment tells that lane.
Gates Dev at 41b3fdf86: 54 derived, 54 run, all exit 0. driver-sql full suite 3692 passed, core test:repo 82 passed. Ablation: the production condition forced false makes the case red and leaves the control green; restored to HEAD.
CI At this read on 41b3fdf86a: ci-failure GREEN, all 41 check-runs completed, none failed.

Disposition:

  • open_questions: both as the dev settled them (record ③): drop_column_default over replace_unique_index, and an explicit NODE_ENV=development control.
  • deviations: all accepted (record ③).
  • out_of_scope_findings: sql-driver-index-drift.test.ts's production case is not vacuous; it meets no filing gate.

Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #24903 then closes the card.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 20, 2026 19:51
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 20, 2026 19:51
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit f32d795 Oct 20, 2026
47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24903-prod-guard-drift-test branch October 20, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants