Repository navigation
Commit cd6d8a5
Fixes #20648
Clause-②: no (narrowing)
The platform reads its deployment ledger (`sys_migration`) one row at a
time, by primary key. Five readers wrote that read as
`find(sys_migration, { where: { id }, limit: 1 })`. The SQL driver
cannot tell that apart from page one of a walk. On a table it has not
registered, it warns that the walk is not deterministic. All five
readers now use `findOne`, the single-row route the driver already
exempts. The driver's check and its wording are unchanged. An unsorted
`limit` read on a table the driver did not create still warns, and a
test pins that control.
## Reproduction on the base, and where the warning came from
**Construction: the 17.4 code path.** A one-object probe app, installed
from npm with every `@objectstack/*` package pinned to 17.4.0 (`npm ls`
shows 261 entries, all 17.4.0). `objectstack dev` on 17.4.0 created a
new SQLite file and booted it three times. Each run below then used a
fresh copy of that file, booted by this branch's base `01e78dceef` (the
same app, wrapped in `defineStack`, which main requires).
| run | code | `Paged read of 'sys_migration'` warnings |
|:--|:--|:--|
| boot 1, 2, 3 on the 17.4 file (control) | npm 17.4.0 | 0, 0, 0 |
| `objectstack dev` on the 17.4 file | base `01e78dceef` | **1** |
| `os migrate plan` on the 17.4 file | base `01e78dceef` | **1** (the
plan also lists `+ sys_migration [add_columns: columns_moved_at]`, as
the card says) |
| `objectstack dev` on a new file (`examples/app-crm`), first boot |
base `01e78dceef` | **1** |
| second boot of that file | base `01e78dceef` | **1** |
So the warning is not specific to upgraded databases. Every boot of main
prints it once, because the read runs before the schema pass registers
`sys_migration` with the driver.
**The producer was not either of the two sites the card names.** I added
a temporary stack-trace line to driver-sql's built `dist/`, behind an
env var, logging every unsorted paged read of a table the driver has not
registered. On boot and on `os migrate plan`, the only such read of
`sys_migration` was `ObjectQL.readMigrationFlagVerified` in
`packages/objectql/src/engine.ts`, reached through
`haveFileColumnsMoved()`. The dist was restored afterwards,
byte-identical to the build: `cmp` against the saved copy matches.
17.4.0 ships the same driver check but has no `haveFileColumnsMoved`,
which is why 17.4.0 prints nothing. By the time the two named sites run
in these compositions, the table is registered, so they order by `id`
and never warn. They still have the defect's shape, so they move too.
Landing site, per the dispatch's producer clause: the engine as well as
the two named files.
## What changed
- **`packages/objectql/src/engine.ts`**: the three `sys_migration` reads
(`readMigrationFlagVerified`, `recordObservedDeviation`,
`retractCreationAttestation`) use `this.findOne(...)`.
- **`packages/platform-objects/src/system/migration-flag.ts`**:
`readDataMigrationFlag` uses `engine.findOne(...)`. The duck-typed
`MigrationFlagEngine` declares `findOne` in place of `find`, since
`find` is no longer called.
-
**`packages/metadata-protocol/src/migrations/seed-tenancy-backfill.ts`**:
the receipt's existence check uses `ledger.findOne(...)`.
`SeedTenancyLedger` declares `findOne` in place of `find`, and
`resolveSeedTenancyLedger` requires `findOne`. The doc comment listing
the ledger's readers now says they read through `findOne`.
- The ObjectQL engine has both methods, and every caller in the repo
passes the engine, so they are unaffected. Only a hand-written stand-in
that offers `find` alone changes behaviour: its read fails, which reads
as "no flag row", and the gates stay closed. The changeset states the
FROM and TO shapes.
**H1 checked.** `ObjectQL.findOne` calls `driver.findOne`, which calls
`findRows(..., singleRowLookup = true)` in `sql-driver.ts`. The options
survive the move. `where: { id }` is a predicate, so
`requireFindOnePredicate` passes. The query's `context: { isSystem: true
}` goes through the same `mergeReadContext(query.context,
options.context)` as on `find`. The platform-objects and
metadata-protocol tests pin the exact call: `findOne('sys_migration', {
where: { id }, context: { isSystem: true } })`.
**H3 checked.** `os migrate plan` makes one unregistered-table read of
`sys_migration`: the engine's gate read through
`haveFileColumnsMoved()`. Neither named site is reached on that path.
The pin is the engine test below.
## After: this branch at `2c59fcaf18`, built
| run | `Paged read of 'sys_migration'` warnings |
|:--|:--|
| `objectstack dev` on a fresh copy of the 17.4.0 file (booted twice
from a build of `4ad574e769`, once from a build of `2c59fcaf18`) | 0 |
| `os migrate plan` on a fresh copy of the 17.4.0 file (from builds of
`4ad574e769` and `2c59fcaf18`) | 0 (the pending `add_columns:
columns_moved_at` line is still listed, as expected) |
| `os migrate plan` on the file this branch's boot had already opened |
0 |
| `objectstack dev` on a new file (`examples/app-crm`), first and second
boot (build of `4ad574e769`) | 0, 0 |
The flag read still answers correctly on the old schema. The plan logs
`this deployment has verified the file-as-reference migration`, read
through `findOne` from a `sys_migration` table that has no
`columns_moved_at` column. `4ad574e769` is the fix before the merge of
`origin/main`, and `2c59fcaf18` is the final head.
## The family sweep: census, and the stop line
The census is AST-based, over non-test `packages/**/*.ts`: a call with
an object-literal argument that has `limit: 1` (a numeric literal) and a
`where`/`filter` object literal with an `id` key, as a shorthand, a
scalar or `{ $eq }`. **Blind spots:** a `where` or `limit` held in a
variable, and a `top: 1` alias. Lit control: both named sites are hits
at the base.
- Base `01e78dceef`: **55 hits in 16 packages.** plugin-approvals 11,
plugin-security 9, plugin-sharing 8, service-automation 7, runtime 4,
objectql 3, plugin-email 3, mcp 2, and one each in metadata-protocol,
platform-objects, plugin-auth, plugin-hono-server, service-datasource,
service-queue, service-settings and service-storage.
- The 5 that read `sys_migration` move here. **50 hits remain in 13
packages** at `2c59fcaf18`.
That is far past the dispatch's ~15-site stop line, and most of the
remainder is in other lanes' packages. Several are not one-line moves:
`runtime/src/action-execution.ts` unwraps `.value` and scans the array,
and `plugin-hono-server`'s is `find.call(ql, ...)`. So they are not
moved here, and the census goes to the seat. None of the 50 printed a
warning in the measured boots. The driver warns only when such a read
reaches a table before the table is registered.
```text
packages/mcp/src/plugin.ts:597
packages/mcp/src/stdio-data-bridge.ts:146
packages/plugins/plugin-approvals/src/approval-service.ts:1346 1548 2030 3030 3630 4126 4943 5008 5417 6401 6795
packages/plugins/plugin-auth/src/admin-set-user-manager.ts:241
packages/plugins/plugin-email/src/attachment-reclaim.ts:202
packages/plugins/plugin-email/src/email-plugin.ts:720 791
packages/plugins/plugin-hono-server/src/current-user-endpoints.ts:570
packages/plugins/plugin-security/src/delegated-admin-gate.ts:1238 1251 1328
packages/plugins/plugin-security/src/permission-set-projection.ts:151
packages/plugins/plugin-security/src/position-catalog-refusal.ts:433
packages/plugins/plugin-security/src/security-plugin.ts:4832 6386 6397 7372
packages/plugins/plugin-sharing/src/business-unit-graph.ts:267
packages/plugins/plugin-sharing/src/primary-bu-projection.ts:108
packages/plugins/plugin-sharing/src/sharing-service.ts:567 951 1008 1416 1484
packages/plugins/plugin-sharing/src/team-graph.ts:189
packages/runtime/src/action-execution.ts:196 217 261
packages/runtime/src/security/actor-user.ts:142
packages/services/service-automation/src/flow-dispatch-store.ts:136 153 205
packages/services/service-automation/src/suspended-run-store.ts:330 360 736 786
packages/services/service-datasource/src/datasource-secret-binder.ts:122
packages/services/service-queue/src/db-queue-adapter.ts:683
packages/services/service-settings/src/settings-service-plugin.ts:403
packages/services/service-storage/src/storage-service-plugin.ts:1183
```
## Tests
-
**`packages/runtime/src/sys-migration-point-lookup.integration.test.ts`**
(new). A real `SqlDriver` over one SQLite file with two driver
instances: the first creates `sys_migration` and writes a flag row. The
second is one the engine knows about but that has not registered the
table. The test asserts `paginationTieBreaker('sys_migration')` is null,
as a stated precondition. It then runs the engine's gate read,
platform-objects' `readDataMigrationFlag`, and the receipt-shaped
`findOne`: zero paging warnings. **Control:** an unsorted
`engine.find('sys_migration', { limit: 1 })` afterwards gives exactly
one warning. It runs last because the warning is once per object per
driver.
- **`packages/objectql/src/sys-migration-single-row-route.test.ts`**
(new). A recording driver double checks each engine reader on the
production path that reaches it: the gate reads, the deviation marker
after a lax-admitted write, and revocation of a contradicted creation
attestation. It asserts that `sys_migration` reaches the driver only as
`findOne`. The probe is lit: a caller's own limit-bound `find` is
recorded as a `find`.
- The existing flag-reader doubles move to `findOne` and are held to
`assertEngineFindOnePredicate`. Files: platform-objects
`migration-flag.test.ts`, `migration-flag.column-move.test.ts`,
`plugin.test.ts`; metadata-protocol `seed-tenancy-backfill.test.ts`;
service-storage `files-to-references-migration.test.ts`,
`lax-deviation-reclamation-gate.test.ts`; objectql `engine.test.ts` (the
#3617 flag block), `value-shape-scan-advisory.test.ts`,
`adr0104-attestation-evidence.test.ts` (the memoization spy).
- Suites, all green:
- objectql `--project local`: 339 files, 6708 tests (after the merge of
`origin/main`).
- platform-objects: 59 files, 948 tests.
- metadata-protocol: 190 files passed, 3 skipped; 2792 tests passed.
- service-storage: 40 files, 627 tests.
- runtime: the new pin plus
`seed-tenancy-autonumber-split.integration.test.ts`, 15 tests.
- Typecheck green for objectql, platform-objects, metadata-protocol,
service-storage, runtime and cli. The `check:test-typecheck` debt is
unchanged, and `--listFiles` confirms both new test files are in their
packages' test programs.
**Ablation**, run from the committed fix. `scripts/ablation-replace.mjs`
reverted `readMigrationFlagVerified` to `find` with `limit: 1`: anchor
hit once, blob `607f1216` to `b828359f`. objectql was rebuilt, and
`ablation-dist-preflight` found the marker in 2 built files. Result: the
runtime pin is **red** (`expected [ Array(1) ] to deeply equal []`), and
the objectql pin is **red** on 3 of 4 cases. The restore was proven
(blob equals HEAD, `git diff HEAD` empty). objectql was rebuilt again,
the preflight `--absent` passed (exit 0, tree clean), and both pins are
green again.
## Gates
`node scripts/pm/dispatch-gates.mjs --commands` at `2c59fcaf18` derives
77 commands, and all 77 ran on that head with exit 0. `--ran`
reconciliation: "77 derived famil(ies) accounted for — 77 run, 0
NOT-MEASURED (a DERIVED zero — all 77 recorded an exit code and none of
them is 3)".
Three gates needed changes on the way:
- `check:engine-double-contract`: the new pinned `findOne` doubles were
recorded with `--write`, which grew the ledger only.
- `check:objectql-double-limit`: ratcheted down for the doubles that no
longer implement a limit-blind `find`.
- `check:query-options-erasure`: the new tests type their options, so
the count stays at its ceiling of 236.
`check:dual-build-cjs-loads` first answered PREREQUISITE NOT MET
(unbuilt packages). It is green after a full `turbo run build`.
## Acceptance notes
- A new database's **first** boot still prints the driver's
`[sql-driver] DATABASE_ERROR — the backend refused a read on
'sys_migration' (SQLITE_ERROR) ... no such table` line once. It did so
before this change and does so after it. It is the same early read, on a
table that does not exist yet. The driver logs it one frame below the
engine, whose own missing-table line is already demoted to `debug`. Not
changed here. Reported to the seat.
- The header table of
`packages/objectql/src/engine-find-missing-table-log-level.test.ts`
still lists `readMigrationFlagVerified` among the `find` callers it
measured. That is a historical reading. The reader now goes through
`findOne`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 91e8fa1 commit cd6d8a5
17 files changed
Lines changed: 591 additions & 75 deletions
File tree
- .changeset
- packages
- metadata-protocol/src/migrations
- objectql/src
- platform-objects/src
- system
- runtime/src
- services/service-storage/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
579 | 579 | | |
580 | 580 | | |
581 | 581 | | |
| 582 | + | |
582 | 583 | | |
583 | 584 | | |
584 | 585 | | |
| 586 | + | |
585 | 587 | | |
586 | 588 | | |
587 | | - | |
588 | | - | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
589 | 597 | | |
590 | 598 | | |
591 | 599 | | |
| |||
674 | 682 | | |
675 | 683 | | |
676 | 684 | | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
677 | 688 | | |
678 | 689 | | |
679 | 690 | | |
| |||
750 | 761 | | |
751 | 762 | | |
752 | 763 | | |
753 | | - | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
754 | 768 | | |
755 | 769 | | |
756 | 770 | | |
| |||
802 | 816 | | |
803 | 817 | | |
804 | 818 | | |
805 | | - | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
806 | 823 | | |
807 | 824 | | |
808 | 825 | | |
| |||
814 | 831 | | |
815 | 832 | | |
816 | 833 | | |
817 | | - | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
818 | 848 | | |
819 | 849 | | |
820 | 850 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1001 | 1001 | | |
1002 | 1002 | | |
1003 | 1003 | | |
1004 | | - | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
1005 | 1011 | | |
1006 | 1012 | | |
1007 | 1013 | | |
| |||
1018 | 1024 | | |
1019 | 1025 | | |
1020 | 1026 | | |
1021 | | - | |
| 1027 | + | |
1022 | 1028 | | |
1023 | 1029 | | |
1024 | 1030 | | |
| |||
1051 | 1057 | | |
1052 | 1058 | | |
1053 | 1059 | | |
1054 | | - | |
| 1060 | + | |
| 1061 | + | |
1055 | 1062 | | |
1056 | 1063 | | |
1057 | 1064 | | |
| |||
1098 | 1105 | | |
1099 | 1106 | | |
1100 | 1107 | | |
1101 | | - | |
| 1108 | + | |
1102 | 1109 | | |
1103 | | - | |
1104 | 1110 | | |
1105 | 1111 | | |
1106 | 1112 | | |
| |||
1110 | 1116 | | |
1111 | 1117 | | |
1112 | 1118 | | |
1113 | | - | |
| 1119 | + | |
1114 | 1120 | | |
1115 | 1121 | | |
1116 | 1122 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
349 | 349 | | |
350 | 350 | | |
351 | 351 | | |
352 | | - | |
| 352 | + | |
| 353 | + | |
353 | 354 | | |
354 | 355 | | |
355 | 356 | | |
| |||
359 | 360 | | |
360 | 361 | | |
361 | 362 | | |
362 | | - | |
| 363 | + | |
363 | 364 | | |
364 | 365 | | |
365 | 366 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2554 | 2554 | | |
2555 | 2555 | | |
2556 | 2556 | | |
| 2557 | + | |
| 2558 | + | |
2557 | 2559 | | |
2558 | 2560 | | |
2559 | 2561 | | |
| |||
2594 | 2596 | | |
2595 | 2597 | | |
2596 | 2598 | | |
2597 | | - | |
| 2599 | + | |
2598 | 2600 | | |
2599 | 2601 | | |
2600 | 2602 | | |
2601 | 2603 | | |
2602 | 2604 | | |
2603 | 2605 | | |
2604 | | - | |
| 2606 | + | |
2605 | 2607 | | |
2606 | 2608 | | |
2607 | 2609 | | |
2608 | 2610 | | |
2609 | 2611 | | |
2610 | 2612 | | |
2611 | | - | |
| 2613 | + | |
2612 | 2614 | | |
2613 | 2615 | | |
2614 | 2616 | | |
2615 | 2617 | | |
2616 | 2618 | | |
2617 | 2619 | | |
2618 | | - | |
| 2620 | + | |
2619 | 2621 | | |
2620 | 2622 | | |
2621 | 2623 | | |
| |||
2631 | 2633 | | |
2632 | 2634 | | |
2633 | 2635 | | |
2634 | | - | |
| 2636 | + | |
2635 | 2637 | | |
2636 | 2638 | | |
2637 | | - | |
| 2639 | + | |
2638 | 2640 | | |
2639 | 2641 | | |
2640 | 2642 | | |
2641 | 2643 | | |
2642 | 2644 | | |
2643 | 2645 | | |
2644 | 2646 | | |
2645 | | - | |
| 2647 | + | |
2646 | 2648 | | |
2647 | 2649 | | |
2648 | 2650 | | |
| 2651 | + | |
2649 | 2652 | | |
2650 | 2653 | | |
2651 | 2654 | | |
2652 | 2655 | | |
2653 | | - | |
| 2656 | + | |
2654 | 2657 | | |
2655 | 2658 | | |
2656 | 2659 | | |
2657 | 2660 | | |
2658 | 2661 | | |
2659 | | - | |
| 2662 | + | |
2660 | 2663 | | |
2661 | 2664 | | |
2662 | 2665 | | |
2663 | 2666 | | |
2664 | 2667 | | |
2665 | | - | |
| 2668 | + | |
2666 | 2669 | | |
2667 | 2670 | | |
2668 | 2671 | | |
2669 | 2672 | | |
2670 | 2673 | | |
2671 | | - | |
| 2674 | + | |
2672 | 2675 | | |
2673 | 2676 | | |
2674 | 2677 | | |
| |||
2735 | 2738 | | |
2736 | 2739 | | |
2737 | 2740 | | |
2738 | | - | |
| 2741 | + | |
2739 | 2742 | | |
2740 | 2743 | | |
2741 | 2744 | | |
| |||
2748 | 2751 | | |
2749 | 2752 | | |
2750 | 2753 | | |
2751 | | - | |
| 2754 | + | |
2752 | 2755 | | |
2753 | 2756 | | |
2754 | 2757 | | |
| |||
2763 | 2766 | | |
2764 | 2767 | | |
2765 | 2768 | | |
2766 | | - | |
| 2769 | + | |
2767 | 2770 | | |
2768 | 2771 | | |
2769 | 2772 | | |
| |||
2782 | 2785 | | |
2783 | 2786 | | |
2784 | 2787 | | |
| 2788 | + | |
2785 | 2789 | | |
2786 | 2790 | | |
2787 | 2791 | | |
2788 | 2792 | | |
2789 | 2793 | | |
2790 | 2794 | | |
2791 | 2795 | | |
2792 | | - | |
| 2796 | + | |
2793 | 2797 | | |
2794 | 2798 | | |
2795 | 2799 | | |
| |||
0 commit comments