Commit c876a74
Fixes #20437
Clause-②: yes (narrowing)
The `Clause-②` line above is the claim's (comment 5876481971), copied as
it stands. The changeset carries the same value.
Session `session_01N8TPEsoJxPsdSdNKGnNGEN` (PM dispatch, `domain:engine`
seat 1, mode:subagent), branch
`claude/issue-20437-replica-needs-syncurl`. The branch starts at
`fc0db22bc` and was merged with `origin/main` at `9bf5e67af` in a true
merge commit. **Every final reading below was taken at head
`7bb7b3aee`** unless it says otherwise.
## What changes
A turso config that forces `mode: 'replica'` on a `file:` url with no
`syncUrl` (or an empty one) is now refused at both doors, with one
message, as triage ruled (5871347046: "Refuse, with one message, at both
doors in one PR"):
- **Authoring.** `tursoTransportIssues` in
`packages/spec/src/data/driver/turso.zod.ts` gains a replica arm after
the in-memory one. It returns one `custom` issue on **`mode`**, the key
that cannot be honoured, as the `sync` refusal sits on `sync`. It
reaches `DatasourceSchema` (as `config.mode`), `validateDriverConfig`,
`defineStack` / `os validate`, and a save or test connection through the
datasource admin service.
- **Construction.** `new TursoDriver()` refuses the same config with
`VALIDATION_ERROR` / 400, before `super()`. The check sits after the
`sync`-without-`syncUrl` refusal, so a config with both defects meets
the `sync` message first, which is also the spec's first issue. The
message is a module constant, `REPLICA_MODE_WITHOUT_SYNC_URL_REFUSAL`,
next to #20200's two, and thrown through the same `refuseIgnoredSyncKey`
helper. The parity table pins it byte-equal to the schema's issue. That
is #20200's pattern (H3).
- **The driver mirror**
(`packages/drivers/driver-turso/src/spec/turso.zod.ts`) carries the same
arm byte for byte. The mirror strips `mode`, so the arm is unreachable
through it (see H4), and it stays for copy parity like the mirror's
other forced-mode branches.
The message, the same text at both doors:
> `mode: 'replica'` makes this datasource an embedded replica, a local
file kept in sync with the remote named in `syncUrl`, but no `syncUrl`
is set: nothing would ever sync, so it would run as a plain local
database that never replicates — the turso driver refuses this
configuration when it starts. For an embedded replica, name the remote
in `syncUrl` beside the local file: `url: 'file:./data/replica.db'` with
`syncUrl` set to the `libsql://` or `https://` Turso endpoint. For a
plain local database, drop `mode: 'replica'`.
It gives both fixes the ruling prescribes: add `syncUrl`, or drop `mode:
'replica'` for a plain local file. It echoes no url and carries no
tracker id.
## H1: the premise, measured before the change
At the base `fc0db22bc`, the existing pins that hold today's answer
passed: 3 files, 38 passed (`-t replica`). They were the parity row
"file: under a forced mode: 'replica'" (constructor accept, spec
accept), the unrecognised-url file's WIDENED `FILE:` + `mode 'replica'`,
no `syncUrl` cell (constructs, and the rows survive a restart), and the
#20200 file's "the rider stays" control. So both schemas accepted the
config, and the constructor built it with `transportMode = 'replica'`.
That half of H1 holds as stated.
The runtime half (`isSyncEnabled()` false, no interval, `sync()` a
no-op) rests on two things. The first is the card's dist probe (the
#20200 dev, at `dbddf02c1` and again at `2242ad513`). The second is the
source at the base: `connect()` builds the sync client only inside `if
(this.tursoConfig.syncUrl)` (`turso-driver.ts:1821`), `sync()` returns
early on `!(this.libsqlClient && this.tursoConfig.syncUrl)` (`:3522`),
and `isSyncEnabled()` is `!!this.tursoConfig.syncUrl &&
this.libsqlClient !== null` (`:3535`). **My own dist probe was NOT
MEASURED**: the session's permission classifier refused writing the
probe script to the scratchpad, so I did not re-run it through another
channel (see Deviations).
## H2: producers, before refusing anything
Census of `mode: 'replica'` / `"replica"` across the tree at
`fc0db22bc`, plus every spelling that builds a `TursoConfig`:
- **examples/, `packages/create-objectstack` (templates), `skills/`,
hand-written `content/docs`**: zero authors of a forced replica. The
only `content/docs` hit is the auto-generated reference row for the
`mode` enum.
- **Environment mappings**: the only `TURSO_*` / `OS_DATABASE_*` names
read in `packages/**/src` are `OS_DATABASE_URL`,
`OS_DATABASE_AUTH_TOKEN`, `OS_DATABASE_DRIVER`, `OS_DATABASE_POOL_MAX`,
`OS_DATABASE_SQLITE_JOURNAL_MODE`, `TURSO_DATABASE_URL`,
`TURSO_AUTH_TOKEN` and `TURSO_TOKEN`. None of them maps to `mode` or
`syncUrl`.
- **Programmatic builders**: a turso `mode` reaches the driver only
through `buildTursoDriverConfig`'s `mode` reader
(`packages/services/service-datasource/src/turso-driver-config.ts:205`),
which reads an authored `datasource.config.mode`. The CLI and the
standalone host build their default datasource from the env url and
token alone.
- **In-repo fixtures that spell `mode: 'replica'`**:
`packages/cli/src/utils/storage-driver.test.ts:478`,
`packages/runtime/src/turso-driver-factory.convergence.test.ts:70/:102`
and
`packages/services/service-datasource/src/__tests__/turso-driver-config.test.ts:49/:60`.
Every one carries a `syncUrl`, and none constructs the real driver.
- **`objectstack-ai/cloud`: NOT MEASURED.** Triage names it. The repo is
not reachable from this session: REST code search answers "sessions are
bound to their configured repositories", and `git ls-remote` is refused.
Attaching it through the session tool was refused by the permission
classifier. The seat or the maintainer should census cloud before this
lands.
So no shipped in-repo config declares a replica with no remote, and the
ruling's `needs_decision` branch does not trigger on anything measured
here.
## H4: every mode / url cell, before and after
| config | before: constructor | before: spec / mirror | after |
| --- | --- | --- | --- |
| `file:`, no `mode`, no `syncUrl` | local | accept / accept | unchanged
(a plain local file, not a replica) |
| `file:` + forced `replica`, no `syncUrl` | replica, never syncs |
accept / accept (the mirror strips `mode` and judges it local) |
**refused** at construction and by the spec, on `mode` |
| the same on an uppercase `FILE:` url | the same (the WIDENED cell) |
accept / accept | **refused** |
| the same with `syncUrl: ''` (unset) | the same | accept / accept |
**refused** |
| the same with `timeoutMs` | the same | accept / accept | **refused** |
| the same with `sync`, no `syncUrl` | refused, `sync` message (#20200)
| 1 issue on `sync` | constructor unchanged (the `sync` message). The
spec now raises 2 issues, `sync` then `mode` |
| `libsql://` + forced `replica`, no `syncUrl` | refused, remote-url
message | refused on `url` | unchanged. It keeps its `url` refusal,
which already names both ways out (drop `mode` or set it remote; or a
`file:` url beside `syncUrl`). Not the same message, and no second
refusal |
| `:memory:` / `file::memory:` + forced `replica` | refused, in-memory
message | refused on `url` | unchanged |
| a bare path + forced `replica` | refused, unrecognised-url message |
refused on `url` | unchanged |
| `file:` + forced `replica` + `syncUrl` | replica | accept / accept |
unchanged (control) |
The "after" column is pinned by the new test file (the refusal, ORDER
and CONTROLS blocks) and by the parity table.
## H5: ADR-0087 disposition — `registered`
The family's entry `turso-config-transport-mismatch-refused` does not
cover this refusal. Its `surface` enumerates the refused combinations (a
remote url beside `syncUrl` or under a forced local/replica mode, an
unrecognised url, an in-memory replica, `timeoutMs` beside a WebSocket
url, and `syncUrl` under a forced remote mode). A forced replica on a
`file:` url with no `syncUrl` is not among them, and its
`acceptanceCriteria` name only `config.url`, `config.syncUrl` and
`config.timeoutMs`. Its `replacement` would fit, but the surface an
upgrading author greps would not name the shape. So, per the order's H5,
a new D3 entry lands with the change:
`packages/spec/src/migrations/entries/semantic/18.turso-config-forced-replica-without-sync-url-refused.ts`,
id `turso-config-forced-replica-without-sync-url-refused`, with its
`surface`, `replacement`, `reason` (the measurement, the order of the
sibling refusals, and what a stored row now does at boot) and
`acceptanceCriteria` (reported at `config.mode`).
`src/migrations/registry.ts` was regenerated by `gen:migration-registry`
(311 semantic), never by hand. **Patch round 1 corrected the entry's
`surface`.** It had named the driver's `TursoConfigSchema` mirror among
the surfaces where this shape "is now refused, on mode". The mirror
cannot refuse it, because it declares no `mode` key and strips an
authored one. The `surface` now names the two doors, the spec contract
and the constructor. It says the mirror carries the arm's text for
parity but cannot see a forced mode and still accepts the config as a
local file (review 5877910448, judgment 4). `registry.ts` was
regenerated again by `gen:migration-registry`. The existing entry is
untouched, because it is #20200's text and stays true. The changeset
carries `registered
turso-config-forced-replica-without-sync-url-refused`, and
`check-adr-0087-registration` reads it as
`[BREAKING+bang+clause-②-narrowing] registered … (new here: …)`.
`spec-changes.json` and `docs/protocol-upgrade-guide.md` do not project
major-18 entries yet (the sibling entry is absent from both too), and
`check:spec-changes` / `check:upgrade-guide` are green.
**Stored rows** (read, not edited): `buildTursoDriverConfig` forwards a
stored row's `mode` unparsed, so a row in this shape now fails at
`factory.create`. `DatasourceConnectionService` records it
`failed-degraded` (`datasource-connection-service.ts:355/:457`), and a
test connection answers `ok: false` with "Failed to build driver:
MESSAGE" (`datasource-admin-plugin.ts:707`). Under ADR-0062 D5 the boot
fails fast when objects bind to it, unless
`OS_ALLOW_DRIVER_CONNECT_FAILURE` is set. The changeset's FROM → TO
paragraph says so.
## Tests
| suite at `7bb7b3aee` | result |
| --- | --- |
| `@objectstack/driver-turso` vitest, whole package | 77 files · 2065
passed · 22 skipped · exit 0 |
| `@objectstack/driver-turso` typecheck (`tsc --noEmit`) | exit 0. `tsc
--listFilesOnly` (pre-merge) counts all 4 touched test files in the
program |
| `@objectstack/spec` vitest `--project local`, 3 shards | 572 files ·
16796 passed · 1 todo (6070 + 5190 + 5536), exit 0 on each shard |
| `@objectstack/spec` typecheck (tsc + scripts + `check:test-typecheck`)
| exit 0 |
| `@objectstack/spec` `check:generated` (pre-merge, after the spec
build) | "All 15 generated artifacts are up to date" |
The 22 skips are the parity table's forced-mode rows for the mirror,
which strips `mode`: 18 before, plus the 4 new `mode` rows.
- **`spec/turso-config-constructor-parity.test.ts`**: the row "file:
under a forced mode: 'replica'" flips from `accept` to `refuse`,
`refusedOn: 'mode'`. Three `mode` rows are added (an uppercase `FILE:`
url, an empty `syncUrl`, and `timeoutMs`), plus an accept control,
"file: + syncUrl under a forced mode: 'replica'". The row "sync with no
syncUrl under a forced mode: 'replica'" now declares `issues: 2`, a new
per-row field (default 1). `SYNC_KEY_REFUSALS` takes the `mode` rows, so
each of the 4 asserts the constructor's message equals the spec issue's.
New floors: `mode` at least 4, sync-key refusals at least 12.
- **`turso-driver-unrecognised-url-refusal.test.ts`**: the WIDENED
`FILE:` + `mode 'replica'`, no `syncUrl` cell leaves PRESERVATION, and
the restart test keeps only its `syncUrl` half. The header records why.
- **`turso-driver-ignored-sync-key-refusal.test.ts`**: the "rider stays"
control is removed, and the header points to the new file.
- **`turso-driver-forced-replica-without-sync-url-refusal.test.ts`
(new)**: the refusal as the envelope (`code` + `status`) plus its first
sentence, on `file:` and `FILE:` urls, beside an empty `syncUrl`,
`timeout`, `encryptionKey`, and a supplied client (the client stays
untouched). It also covers `createTursoDriver()` and a url-echo check.
ORDER: a remote url, `:memory:`, `file::memory:`, a bare path and `sync`
each keep their own refusal. CONTROLS: a forced replica beside `syncUrl`
connects, reports sync on and keeps its rows across a restart; a replica
selected by `syncUrl`; `file:` with no `mode`; `mode: 'local'`;
`:memory:`; and `detectMode` still answers `replica`.
- **`packages/spec/src/data/driver/turso.test.ts`**: the accept fixture
`{ url: 'file:./data/replica.db', mode: 'replica' }` gains a `syncUrl`.
A new block asserts the refusal on `mode` (the envelope, the first
sentence, both ways out), that the url refusals keep their order, the
two issues beside `sync`, both authoring doors (`config.mode` and
`validateDriverConfig`), and the controls.
**Reverse verification**, via `scripts/ablation-replace.mjs` from the
committed state, pre-merge head `79fbad660`. Each direction was
predicted before the run, and all three matched:
1. Constructor refusal disabled: `if (mode === 'replica' &&
!config.syncUrl) {` became `if (false && …) {`, and the mutation landed
(anchor 1 → 0, blob `8c7f7be9` → `a0c11cd6`). Predicted 16 RED. Got **16
failed** / 236 passed: the new file's 8 refusal cases, plus the parity
table's 4 constructor verdicts and 4 message pins. ORDER and CONTROLS
stayed green. Restored: blob == HEAD, `git diff HEAD` empty.
2. One byte of the copy: a doubled space after the constant's first
sentence (blob → `e70d75a1`). Predicted exactly the 4 message pins. Got
**4 failed**: exactly the 4 parity message pins, while every verdict and
first-sentence case stayed green. The byte-equality pin is what holds
the copy. Restored the same way.
3. The spec arm disabled in `packages/spec/src/data/driver/turso.zod.ts`
(blob `fdfb4a6f` → `0634285e`), against the spec's own source-level
test. Predicted 3 RED. Got **3 failed** / 31 passed: the refusal, the
two-issue and the both-doors cases. The order and control cases stayed
green. Restored the same way.
The driver tests import the driver from `src`, so ablations 1 and 2
needed no build. Ablation 3 was read on the spec's own source tests
only; the parity table's spec half reads the built spec dist, and that
was not re-ablated.
## Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, run after the last commit at `7bb7b3aee`,
lists 11 paths vs merge base `9bf5e67af` and **91 commands**. Every
command ran, with its exit code written to disk before any pipe. `--ran`
reconciliation reads `91 derived famil(ies) accounted for — 89 run, 2
NOT-MEASURED (2 DERIVED from a recorded exit 3)`, with 0 UNRUN.
- **NOT MEASURED (exit 3, PREREQUISITE NOT MET):**
`check:dual-build-cjs-loads` (dozens of workspace packages have no
`dist/`) and `check:type-check-debt` (it needs a whole-workspace build).
Both are CI's run.
- **Run twice:** `check:doc-formula-expressions` and
`check:lean-entry-closure` first answered exit 3. They are exit 0 after
building the `@objectstack/lint` and `@objectstack/objectql` closures.
- **Notable readings:**
- `check-adr-0087-registration` → `registered
turso-config-forced-replica-without-sync-url-refused` (new here),
BREAKING, bang, clause-② narrowing;
- `check-changeset-no-major` exit 0;
- `check:migration-registry` → `registry.ts is current (311 semantic,
230 retired-key, 206 retired-def)`;
- `check:driver-conformance`, `check:nul-bytes`, `check:doc-authoring`,
`check:test-source-alias`, `check:cross-package-test-inputs`,
`check:api-surface` ("unchanged"), `check:authorable-surface`,
`check:docs`, `check:spec-changes`, `check:upgrade-guide` and
`check-empty-changeset` → exit 0.
- **Roster families under a touched directory, also run:**
`check-changeset-fixed`, spec `check:meta-url-spelling`,
`check:authz-resolver`, `check:error-code-casing` and
`check:filter-alias-parity`, all exit 0.
- **Narrowed lint:** `eslint --no-inline-config --format json` over the
10 changed TS files reports 10 files, 0 errors and 0 warnings. The
population is `eslint.config.mjs`'s lint object, `files:
['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']`; the changeset `.md` is
outside it. Invariance holds because the config enables no type-aware
linting (no `parserOptions.project`), so this diff cannot move any
untouched file's verdict. The full `pnpm lint` is CI's.
- **Not run locally, left to CI:** the whole-workspace type-check lanes;
the Test Core, Dogfood and Build Core jobs; and the downstream suites of
`@objectstack/service-datasource`, `@objectstack/runtime` and
`@objectstack/cli`. The narrowing is declared: the public surface's
bytes are unchanged (`check:api-surface` and `check:authorable-surface`
are green, and refinements are not in the JSON Schema). The fixture
census above finds no consumer fixture that spells the refused shape,
and none that constructs the real driver with a forced mode.
**Driver-conformance ledger (`lanes/engine.md`):**
`check:driver-conformance` read `OK — 50 covered cell(s), 0 in the DEBT
ledger, 0 exempt` both before (`fc0db22bc`) and after (`7bb7b3aee`).
`driver-turso` is `ok` on all 10 case-sets both times. No movement.
## Deviations (declared)
- **H1 dist probe not re-run.** Writing a scratch probe script was
refused by the session's permission classifier. The runtime half rests
on the card's cited probe and the base source lines above, and the
constructor/schema half on the existing pins at the base.
- **Cloud producers not measured** (H2): the repo is unreachable from
this session, and attaching it was refused. Nothing in-repo triggers
`needs_decision`.
- **Parity harness:** a per-row `issues` count (default 1) was added for
the one row where the spec now raises two issues. The alternative was to
suppress the `mode` issue when `sync` also fires, which would couple the
two arms. Raising both matches how the schema reports every other
independent defect.
- **Issue path `mode`:** the triage ruling names the message, not the
key. `mode` was chosen by the sibling convention (the `sync` refusal
sits on the present, unhonourable key). `TursoTransportIssue.path`
widens to include `'mode'` in both copies (module-local types, no
export).
## Acceptance notes
- `packages/drivers/driver-turso/README.md`'s list of constructor
refusals named only the url refusals. **Patch round 1 adds** this
refusal and #20200's two sync-key refusals, one line each. It is docs
text only and outside the claim's letter, so it is declared as a
deviation.
- The spec's `mode` key keeps its one-line TSDoc. The requirement is
carried by the refusal text and by `TursoDriverConfig.mode`'s TSDoc in
the driver, which now names it. That avoids a describe/TSDoc
regeneration lap for no authoring gain.
- The existing D3 entry `turso-config-transport-mismatch-refused` is
untouched. Its "Nothing the constructor accepts is refused" stays true,
because both doors refuse this shape together.
## Patch round 1 (text only, head `5dfa45e9f`)
This round follows the at-tier review 5877910448 (PASS at `7bb7b3aee`;
judgment 4 names one wrong clause). It makes two edits and changes no
code, test, schema text or message:
1. **The D3 entry
`turso-config-forced-replica-without-sync-url-refused`**: its `surface`
no longer lists the driver mirror among the refusing surfaces. It now
names the spec contract and the constructor, and says what the mirror
does (the H5 note above). `registry.ts` was regenerated by
`gen:migration-registry`, and its hunk equals the entry's, re-indented.
The sibling family entry `turso-config-transport-mismatch-refused` is
not edited here; the seat carries its same overstatement as a note.
2. **`packages/drivers/driver-turso/README.md`**: the list of
constructor refusals gains one line each for `syncUrl` under a forced
`mode: 'remote'`, `sync` with no `syncUrl`, and a forced `mode:
'replica'` with no `syncUrl`, in the list's own style. This is a
declared deviation (docs text, outside the claim's letter).
The head is `6a076723d` (the text commit) plus a true merge of
`origin/main` at `4a1df1965`. The merge touched no migrations or turso
path, and `gen:migration-registry` after it wrote no change. Readings at
`5dfa45e9f`, each exit code recorded before any pipe:
- `pnpm --filter @objectstack/spec check:migration-registry` exit 0:
`registry.ts is current (311 semantic, 230 retired-key, 206
retired-def)`;
- `pnpm check:adr-0087-registration` exit 0:
`[BREAKING+bang+clause-②-narrowing] registered
turso-config-forced-replica-without-sync-url-refused (new here …)`;
- spec `check:spec-changes`, `check:upgrade-guide`,
`check:doc-authoring`, `check:nul-bytes` and `check-changeset-no-major`
all exit 0;
- spec vitest `--project local` over `src/migrations`, `src/conversions`
and `src/data/driver`: 22 files, 1044 passed, exit 0.
`dispatch-gates --commands` at this head derives the same 91 commands as
round 0 (12 paths vs merge base `4a1df1965`; the README adds no family).
The full union was not re-run for this text-only delta. The round-0
union at `7bb7b3aee` stands, and CI measures this head.
## Patch round 2 (merge + form D), head `519cfbce5`
This round follows the maintainer's ruling recorded in 5883364572,
「20504 不考虑 cloud 现有数据」: the cloud producer census stays NOT MEASURED,
waived by the maintainer, and nothing in `objectstack-ai/cloud` was read
or edited. The round changes no code, test, schema text, refusal message
or changeset. The changeset's level and the `Clause-②` line do not move.
1. **The merge.** `origin/main` at `1c761c0d7` was merged into the
branch in a true merge commit, `04be827ce` (parents `5dfa45e9f` and
`1c761c0d7`), by `bash scripts/pm/os-regen-merge.sh`. There was no
rebase and no force-push. Since the old base `4a1df1965`, main had moved
over two of this PR's files, and both auto-merged with no conflict:
- `packages/spec/src/migrations/registry.ts` (generated): stages 4–6 of
the guidance rewrite restated other entries, and new entries landed.
- `packages/drivers/driver-turso/src/turso-driver.ts`: the `$empty`
value-shape resolver wiring and the `$empty` presence-flag case. The
merged file carries both sides: `setDeclaredValueShapeResolver` and
`case '$empty':` sit beside `REPLICA_MODE_WITHOUT_SYNC_URL_REFUSAL`.
`packages/spec/src/data/driver/turso.zod.ts` did not move on main in
that window. The merge left no os-regen deferral.
2. **Regeneration, with the repo's own tooling.** `pnpm --filter
@objectstack/spec check:migration-registry` read the textually merged
`registry.ts` as current (315 semantic, 232 retired-key, 206
retired-def), and `pnpm --filter @objectstack/spec
gen:migration-registry` then wrote no change. After the entry edit in
item 3, `gen:migration-registry` ran again, and its `registry.ts` hunk
is the entry's hunk re-indented (+4 / −1 in each file).
`spec-changes.json` and `docs/protocol-upgrade-guide.md` still project
no major-18 entry. `check:spec-changes`, `check:upgrade-guide` and `pnpm
--filter @objectstack/spec check:generated` ("All 15 generated artifacts
are up to date", after the spec build at this head) are green, so no
other artifact needed regenerating. Against the new merge base the net
diff is 12 files, +539 / −43.
3. **Form D in the entry's `reason`.** The file is
`18.turso-config-forced-replica-without-sync-url-refused.ts`, and
`reason` is the `why:` line `os migrate meta` prints. The id, `surface`,
`replacement`, `acceptanceCriteria`, the registration and the ADR-0087
disposition (`registered
turso-config-forced-replica-without-sync-url-refused`) are unchanged.
Only the opening moves:
- **Before:** "`#20437`. An embedded replica is a local file kept in
sync with the remote named in syncUrl. A forced mode replica with no
syncUrl parsed clean at authoring, …"
- **After:** "An embedded replica is a local file kept in sync with the
remote named in syncUrl, so a replica is defined by its remote. The
ruling of 2026-09-28 weighed refusing this shape against documenting a
replica with no remote as a local mode, and refused it: with no remote
there is no replica mode to document, only a declaration nothing
honours. A forced mode replica with no syncUrl parsed clean at
authoring, …"
The rest of `reason` is byte-identical. The date and the lesson are
triage's ruling (5871347046): an embedded replica is defined by its
remote, so there is no legitimate local replica mode to document
instead. The four author-shown fields were evaluated with their string
literals joined, and scanned with the CLI pin's detector (`#` followed
by 4 or 5 digits). Each field reads 0 now. The lit control is the same
probe over the entry at `5dfa45e9f`, which reads 1 in `reason`. No test
asserted the old sentence, so nothing was re-pinned. The CLI pin
`migrate-meta-engine-guidance.test.ts` selects entries by id prefix, and
`turso-` is not one of its covered families, before or after stage 7 on
main. No other test quotes the text. The sibling
`turso-config-transport-mismatch-refused` still opens with a tracker
number, and it is untouched, as ordered.
**Readings at `519cfbce5`, the head measured.** Each exit code was
recorded before any pipe.
- **Builds.** `turbo run build` over the `@objectstack/driver-turso`,
`@objectstack/lint` and `@objectstack/objectql` closures: 15 tasks, exit
0.
- **`@objectstack/driver-turso`.** Vitest over the whole package: 78
files, 2108 passed, 22 skipped, exit 0. Typecheck exit 0, and `tsc
--listFilesOnly` counts all 4 touched test files.
- **`@objectstack/spec`.** Vitest `--project local` in 3 shards: 574
files, 16884 passed, 1 todo (6106 + 5220 + 5558), exit 0 on each shard.
Typecheck (tsc, scripts and `check:test-typecheck`) exit 0.
- **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` lists 12 paths vs merge base
`1c761c0d7` and 91 commands, and all 91 ran. `--ran` reads "91 derived
famil(ies) accounted for — 89 run, 2 NOT-MEASURED (2 DERIVED from a
recorded exit 3)". The 2 NOT MEASURED are `check:dual-build-cjs-loads`
and `check:type-check-debt`, both PREREQUISITE NOT MET because they need
a whole-workspace build. CI runs both.
- **Gates the order names.** `pnpm check:doc-authoring` exit 0. `pnpm
check:adr-0087-registration` exit 0: the self-test holds 441 assertions,
and the gate reads `[BREAKING+bang+clause-②-narrowing] registered
turso-config-forced-replica-without-sync-url-refused (new here …)`.
`pnpm --filter @objectstack/spec check:migration-registry` exit 0 (315
semantic). `check:spec-changes`, `check:upgrade-guide`,
`check:release-spec-changes`, `check-changeset-no-major --base
origin/main` and `check:nul-bytes` exit 0. `check:doc-authoring` does
not read a migration entry's prose fields: patch round 1 recorded it
green at `5dfa45e9f` with the number still present. So the proof for
item 3 is the field census above.
- **Roster families under a touched directory.**
`check-changeset-fixed`, spec `check:meta-url-spelling`,
`check:authz-resolver`, `check:error-code-casing` and
`check:filter-alias-parity`, all exit 0.
- **Narrowed lint.** `eslint --no-inline-config --format json` over the
10 changed TS files reports 10 files, 0 errors and 0 warnings. The
population is `eslint.config.mjs`'s `files:
['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']`. The config enables no
type-aware linting, so this diff cannot move an untouched file's
verdict.
- **Main moved after the merge.** It is now at `f11b5f20a`, stage 7 of
the guidance rewrite, which touched `registry.ts` and other families'
entries. A driver-free probe (a bare shared clone, `merge-tree
--write-tree`) merges this head with it cleanly.
`build-migration-registry.ts --check` over the probed tree reads
`registry.ts` as current (315 semantic). The branch was not merged again
this round.
**Deviations (declared).** The branch took two pushes this round, the
merge commit and then the reword commit, following AGENTS.md's
push-before-every-long-step rule. The merge commit carries no trailer.
The reword commit ends with the model-free trailer pair.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01N8TPEsoJxPsdSdNKGnNGEN)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent c9d234c commit c876a74
12 files changed
Lines changed: 539 additions & 43 deletions
File tree
- .changeset
- packages
- drivers/driver-turso
- src
- spec
- spec/src
- data/driver
- migrations
- entries/semantic
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
226 | 238 | | |
227 | 239 | | |
228 | 240 | | |
| |||
Lines changed: 29 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
| |||
74 | 77 | | |
75 | 78 | | |
76 | 79 | | |
77 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
78 | 83 | | |
79 | 84 | | |
80 | 85 | | |
| |||
97 | 102 | | |
98 | 103 | | |
99 | 104 | | |
100 | | - | |
| 105 | + | |
101 | 106 | | |
102 | 107 | | |
103 | 108 | | |
| |||
147 | 152 | | |
148 | 153 | | |
149 | 154 | | |
150 | | - | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
151 | 158 | | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
152 | 165 | | |
153 | 166 | | |
154 | | - | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
155 | 171 | | |
156 | | - | |
| 172 | + | |
157 | 173 | | |
158 | 174 | | |
159 | 175 | | |
| |||
209 | 225 | | |
210 | 226 | | |
211 | 227 | | |
212 | | - | |
| 228 | + | |
| 229 | + | |
213 | 230 | | |
214 | 231 | | |
215 | 232 | | |
| |||
229 | 246 | | |
230 | 247 | | |
231 | 248 | | |
232 | | - | |
| 249 | + | |
233 | 250 | | |
234 | 251 | | |
235 | 252 | | |
| |||
241 | 258 | | |
242 | 259 | | |
243 | 260 | | |
244 | | - | |
245 | | - | |
246 | | - | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
247 | 265 | | |
248 | | - | |
| 266 | + | |
249 | 267 | | |
250 | 268 | | |
251 | 269 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
158 | | - | |
| 158 | + | |
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
242 | 260 | | |
243 | 261 | | |
244 | 262 | | |
| |||
0 commit comments