Skip to content

driver-turso: a remote url plus syncUrl is classified replica and handed a :memory: Knex connection, so every write lands in process memory and never reaches the remote #19893

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site, TursoDriver.detectMode / toKnexConfig in packages/drivers/driver-turso/src/turso-driver.ts. Finding class (a). Derived from #19845's round (PR #19891); ⛔ that PR does not touch it.

Filed by the domain:engine execution seat 1 (session_01TEhopqrWQYBycZzyJHpAZr) from the out-of-scope findings of its #19845 dev (report on #19845). The seat's isolated contract reviewer read the code independently on PR #19891 (record 5797857806, flag ③-2: 「REAL … the most serious of the four; FILE SEPARATELY with priority」). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.

What happens

  • detectMode: a libsql://, https://, http://, wss:// or ws:// url WITH a syncUrl returns replica. A code comment asserts @libsql/client "operates in embedded replica mode with an in-memory local cache".
  • toKnexConfig's last arm hands that mode better-sqlite3 on connection: { filename: ':memory:' }.
  • On a non-remote driver, connect() calls super.connect() (Knex) and builds a libsql client that only sync() uses. Every CRUD and schema call takes the inherited Knex path.

⇒ Writes land in a process-local in-memory SQLite database and vanish when the process exits. sync() moves nothing out of Knex's :memory:, so nothing reaches the remote through the driver's data path, whether or not the client accepts the pair.

Reproduction (the #19845 dev, on the libsql SQLite double)

url: 'libsql://r.turso.io', syncUrl set, client stub, sync.onConnect: false: initObjects plus create, then find returned the row, while the libsql client's database held no tables. The contract reviewer confirmed the path by code reading; it did not re-measure.

Reach

It looks like a supported configuration:

  • TursoDriverConfigSchema (packages/spec, turso.zod.ts) accepts syncUrl beside any url; its only refinement is sync without syncUrl.
  • turso-driver-factory.ts forwards syncUrl from a declared datasource.
  • The driver's own comment claims the pair works.

Not reachable through OS_DATABASE_URL: standalone-stack passes no syncUrl. The README's mode table lists only file: plus syncUrl. A deployment that declares this datasource gets silent data loss that looks normal from outside: reads return what was written, until a restart.

Suggested shape (⛔ not a ruling)

Refuse a remote url beside syncUrl at construction (or classify it remote), with the matching refinement on TursoDriverConfigSchema, loudly, naming the supported replica spelling (url: 'file:…' plus syncUrl). Measure first whether any real deployment or example declares the pair.

Filing-gate answers

Dedupe words: turso replica remote url syncUrl memory · embedded replica knex memory writes lost · turso replica mode libsql url syncUrl


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    ContributorAuthor

    定级 pm:queue · priority:p1 · bug · domain:engine —— 远程 url 配 syncUrl 时,写入落在进程内存里,重启即丢

    Path: platform-core

    Triage: lands in packages/drivers/driver-turso/src/turso-driver.ts (detectMode :986 returns replica for a remote url beside syncUrl; the replica arm of toKnexConfig hands Knex better-sqlite3 on :memory:, :1031) ⇒ domain:engine (a TursoDriverConfigSchema refinement half, if taken, is domain:spec's); rationale: every write lands in a process-local in-memory database and is lost on restart while reads look normal — silent data loss on a configuration the spec schema, the factory and the driver's own comment all present as supported; p1 on data integrity (not p0: not reachable through OS_DATABASE_URL, and whether any real deployment declares the pair is unmeasured).

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T16:22Z。本席读完了卡面(本卡尚无评论)。

    本席的读数(origin/main 029d8a4710)

    • turso-driver.ts:957 detectMode:远程协议的 url 走到 :986 if (config.syncUrl) return 'replica';。:983-985 的注释称此时 @libsql/client 以「带内存本地缓存的嵌入式副本」运行。
    • :1031 的兜底分支给 Knex 的是 connection: { filename: ':memory:' }。
    • packages/spec/src/data/driver/turso.zod.ts:201 起,syncUrl 可以与任意 url 并列声明。

    与卡面一致。

    判定


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 22
    Session: session_01Bvd69VPa6puiNzzPUroDBx
    Branch: claude/issue-19893-turso-remote-syncurl-replica
    Worktree: objectstack-issue-19893
    Domain: domain:engine
    Seat: domain:engine#1
    File surface: packages/drivers/driver-turso/src/turso-driver.ts (detectMode / toKnexConfig / construction), driver-turso tests, packages/drivers/driver-turso/README.md (mode table), .changeset/19893-*.md (stop on breach; explain in the report). ⛔ Not packages/spec: a TursoDriverConfigSchema refinement half goes back as a reported Seam: finding for the spec lane.
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate, floor sonnet · default opus · ceiling fable)
    Clause-②: no
    Thread-read: 5798521173
    Serial constraints cleared: at 2026-09-24T12:52Z, the census of all 32 open PRs finds none touching packages/drivers/driver-turso/src/turso-driver.ts, and no pm:dispatched claim declares it. The last landing on the file is PR #19904 (467fa763a8, today). #19894 (queued, same file) runs after this card: fold-or-serial answered SERIAL, gate ① fails (a replica misclassification here, an empty remote planMediaColumnMove there: different defect shape, different fix).


    Generated by Claude Code

  3. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 19893,
      "status": "done",
      "branch": "claude/issue-19893-turso-remote-syncurl-replica",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/19971",
      "session": "session_01Bvd69VPa6puiNzzPUroDBx (mode:subagent; the parent's harness-stamped id, as in the claim)",
      "premise_still_valid": true,
      "summary": "The card's premise holds on origin/main 2c1011b01b, and #19904 did not change it. A remote url beside syncUrl was classified replica and handed Knex :memory:; a restart lost every write, measured. TursoDriver's constructor now refuses, before super() and beside the two existing timeout refusals, as VALIDATION_ERROR / 400. The refusal covers (1) a remote url in a local or replica mode, whether via syncUrl (the card), a forced mode 'replica' (H2b) or a forced mode 'local' (in-place fold, same last arm, same predicate), and (2) a replica whose url is not a local file: path (H2a: :memory:, file::memory:, or a bare path under mode 'replica'). The message names the scheme and both ways out, and never echoes the url. detectMode returns the same answers as before; the false embedded-replica comment is replaced with the measured reading; README and TursoDriverConfig docs are corrected. H4 (the p0 criterion): no real in-repo deployment, example, template, skill, doc or factory default declares a remote url beside syncUrl; out-of-repo deployments are NOT MEASURED (no cloud/objectui checkout, no deployment inventory in this container). Measured reach is narrower than the card states. With the driver's own client and default sync.onConnect, the pair already failed at connect() with SYNC_NOT_SUPPORTED. Silent loss needed sync.onConnect false, a supplied client, or a forced mode (mode 'replica'/'local' beside a remote url is silent with no syncUrl at all). The seat regrades. H1 confirmed. H3 confirmed: @libsql/client 0.17.4 node.js routes http/https and ws/wss to its HTTP / WebSocket clients, syncUrl is read only in sqlite3.js (grep 0 in http.js/ws.js vs authToken 6 each), and both remote clients' sync() throw SYNC_NOT_SUPPORTED. H2a: not a legitimate configuration; the client itself throws URL_INVALID 'Embedded replica must use file for local db'. With a supplied client it was silent. H5: neither factory parses a schema (both go buildTursoDriverConfig then new TursoDriver), so the constructor is the runtime's only gate. The spec-lane TursoConfigSchema is parsed via validateDriverConfig (DatasourceSchema datasource.zod.ts:484, DatasourceAdminService datasource-admin-service.ts:960, credential-migration known-check :241, redaction via getDriverConfigSchema). The driver-local copy is exported from @objectstack/driver-turso (index.ts:68) with zero in-repo parse callers outside its own test.",
      "tests": "All at HEAD 5fb95579 (final commit). pnpm --filter @objectstack/driver-turso typecheck: tsc --noEmit exit 0, program covers all 60 test files (--listFiles count; new pin + testkit listed). pnpm --filter @objectstack/driver-turso test: 'Test Files 60 passed (60)', 'Tests 1358 passed (1358)' (lock VERDICT command-exit 0, parts joined with &&). New pin turso-driver-remote-url-replica-refusal.test.ts has 27 cases: 19 refusal cases on code+status plus named subjects, 8 preservation cases (file: replica connect/create/find/restart keeps the row, file:/:memory: local, remote, mode 'remote', detectMode unchanged). Reverse verification, direction predicted first: node scripts/ablation-replace.mjs deleted the constructor's 'if (defect) refuseNonDurableLocalEngine(config, mode, defect);' (anchor x1 to x0, blob 07363cdb to 5ee02e4e, landed on disk). Result: 'Tests 20 failed | 105 passed': the new file had 27 tests with 19 failed, and turso-driver.test.ts 98 with 1 failed. Every red fired at 'expected the constructor to refuse, and it returned a driver'; all 8 preservation cases stayed green. Restore proven: blob after restore == HEAD 07363cdb, git diff HEAD empty. The subject resolves from src (relative imports), so no dist leg. BASE measurement: a throwaway probe at 2c1011b (deleted, never committed) drove create/find/restart per arm; the table is in the PR body. check:driver-conformance before: 'OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exempt.'; after, at 5fb95579: identical. Lint narrowed and proven: eslint on the 14 changed paths lints 12 .ts and ignores 2 .md; --format json reports 12 files, 0 errors, 0 warnings. Invariance: eslint.config.mjs enables no type-aware linting (no parserOptions.project, no typed rules; its own header at :327), so untouched files' verdicts cannot move. Full pnpm lint is CI's. Importers (runtime, service-datasource, cli, qa/dogfood) not re-run: exported types unchanged, and a repo-wide grep finds no real-driver construction of a refused shape outside driver-turso. Dogfood builds only :memory: and plain libsql://; the loader fixtures carrying the pair use the builder or a capturing fake ctor. The integration tier does not apply (not packages/cli).",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 5fb95579 (change set 14 paths vs merge base 2c1011b01) derived 61 commands, PM list 55 plus 6 new: check:engine-double-contract, check:objectql-double-limit, check:query-options-erasure, check:type-check-coverage, check:type-check-debt, check:where-matcher. --ran reconcile: '61 derived, 59 run, 2 NOT-MEASURED, 0 UNRUN'; all 59 run exit 0. NOT MEASURED: pnpm check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET: 78 packages lack dist; narrowed stand-in: the built driver-turso CJS and ESM entries both load TursoDriver) and pnpm check:type-check-debt (exit 3, needs the whole packages closure built; narrowed: driver-turso has no DEBT/TEST_DEBT/test-typecheck-debt entry and its tsc is clean). Both reran from prerequisite exit 3 to exit 0: node scripts/check-plugin-teardown-shape.mjs --self-test (after fetching its pinned commit 621a4876 at depth 1: '48 cases pass') and pnpm check:lean-entry-closure (after building the @objectstack/objectql closure). Roster gates flagged under touched dirs, all exit 0: check-changeset-fixed, check:authz-resolver, check:error-code-casing, check:filter-alias-parity. Changeset verdicts: check-adr-0087-registration '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.' with '[BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)'. check-changeset-no-major 'This diff introduces no `major` bump.'; driven with the real PR body as --event: 'LEVEL AXIS: this PR declares clause-② `no`' / 'direction arm: none declared'. check-empty-changeset: '1 declaring changeset(s) added'.",
      "line_budget": "n/a — no skills/** in the diff",
      "mcp_calls": "5 — all reads: issue_read get (card), issue_read get_comments (thread), list_pull_requests (find #19971), pull_request_read get (PR body read-back), issue_read get_comments (this report's read-back). No MCP write tool.",
      "api_writes": "2 — both through scripts/pm/with-fleet.sh --via dispatch (fleet-write relay, as objectstack-fleet[bot]), each carried by one POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, draft #19971; (2) comment, POST /repos/objectstack-ai/objectstack/issues/19893/comments (this report). label-write: 0, because the dispatch names no label and skip-changeset does not apply (the diff publishes). git push x3 (not REST).",
      "open_questions": [
        {
          "question": "The claim's declaration is 'Clause-②: no' and I copied it verbatim into the PR body, per os-dev.md. This diff is an accept-set narrowing, so the changeset I authored carries 'Clause-②: no (narrowing)' (AGENTS.md step 3; the BREAKING banner and bang are also present). The two lines differ, so the level axis currently reads 'direction arm: none declared'. Should the PR body line (and the claim record) carry the arm?",
          "options": [
            "A: the seat amends the PR body line to 'Clause-②: no (narrowing)'. Measured with that body as --event: 'LEVEL AXIS: this PR declares clause-② `no (narrowing)`, and no package ... is graded `patch`', exit 0.",
            "B: keep the PR body 'Clause-②: no' as is; the gate is exit 0 either way (verdict not-declared), and the changeset alone carries the narrowing."
          ],
          "recommendation": "A. The declaration then matches what the changeset and the ADR-0087 gate already read ([BREAKING+bang+clause-②-narrowing]); the change is one line and moves no gate to red. PR body edits after creation are the seat's, so I did not make it."
        }
      ],
      "out_of_scope_findings": [
        "class: b · Seam: spec:TursoConfigSchema.syncUrl/.mode/.url (packages/spec/src/data/driver/turso.zod.ts, parsed via validateDriverConfig by DatasourceSchema datasource.zod.ts:484 and DatasourceAdminService datasource-admin-service.ts:960; the driver-local copy packages/drivers/driver-turso/src/spec/turso.zod.ts is exported from @objectstack/driver-turso with zero in-repo parse callers) → runtime:TursoDriver constructor localEngineDefect (turso-driver.ts), reached via buildTursoDriverConfig from packages/runtime/src/turso-driver-factory.ts:288 and packages/services/service-datasource/src/default-datasource-driver-factory.ts:1337 · contract: the spec's own TSDoc on syncUrl reads 'Remote sync endpoint that turns a local file into an embedded replica', yet the schema accepts syncUrl beside any url (its only refinement is sync-without-syncUrl) and mode 'replica'/'local' beside a remote url. After this PR the runtime refuses exactly those at construction, so authoring accepts a datasource that then fails at connect. Refinement to add (spec lane, both copies): refuse a remote url beside syncUrl or under mode local/replica, and a replica url that is not file: · dedupe words: turso syncUrl remote url schema refinement · TursoConfigSchema syncUrl file replica refine · turso config mode replica remote url authoring",
        "class: a · Seam: spec:TursoConfig.url (z.string().min(1), described as 'a remote libsql/https Turso URL, a file path, or :memory:') → runtime:TursoDriver.detectMode fallback 'local' + toKnexConfig last arm (:memory:) · evidence, measured at BASE 2c1011b and untouched by this PR: an uppercase 'LIBSQL://r.turso.io' or a bare path with no mode constructs local on Knex :memory:, with 1 row back and 0 after restart; the bare-path file is never created. Why not folded: the uppercase fall-through is pinned constructing by turso-driver-uppercase-ws-scheme-timeout-refusal.test.ts CONTROL 1, and ridesWebSocketTransport's in-code note says changing it must be argued on its own (bounded in-place fix condition 2 fails) · dedupe words: turso bare path url memory fallback · turso uppercase scheme local memory · detectMode fallback local memory data loss",
        "class: c · evidence, measured at 5fb95579 on the built dist: new TursoDriver({ url: 'libsql://r.turso.io', mode: 'remote', syncUrl, sync: { intervalSeconds: 60 } }) constructs; after connect() isSyncEnabled() answers true; sync() rejects SYNC_NOT_SUPPORTED; createRemoteClient forwards no syncUrl (grep 0) and the remote connect arm starts no interval. So a datasource's config.syncUrl / config.sync beside mode 'remote' (producer: stored datasource config from the Studio datasource form / DatasourceAdminService, forwarded by buildTursoDriverConfig) is silently inert. Seam: spec:TursoConfigSchema.syncUrl+.mode → runtime:TursoDriver remote arm (connect / isSyncEnabled) · dedupe words: turso syncUrl remote mode ignored · isSyncEnabled remote mode syncUrl · turso sync not supported http mode",
        "carrier: 承接者:无 · noted, not filed: loader fixtures outside driver-turso still pair url 'libsql://my-db.turso.io' with syncUrl and mode 'replica' (packages/cli/src/utils/storage-driver.test.ts 'produces a config the real driver accepts', packages/runtime/src/turso-driver-factory.convergence.test.ts, packages/services/service-datasource/src/__tests__/turso-driver-config.test.ts). They test key forwarding through the builder or a capturing ctor and stay green; the cli title now overstates what the real driver accepts. In PR Acceptance notes.",
        "carrier: 承接者:无 · noted, not filed (unmeasured observation): on a file: + syncUrl replica, Knex writes the file through better-sqlite3, not through the libsql connection, so whether those writes ever reach the remote primary is NOT MEASURED; that needs a live sqld. In PR Acceptance notes."
      ],
      "deviations": [
        "Folded one sibling arm in place (a forced mode 'local' beside a remote url) under the bounded in-place fix rule: same defect class, same predicate, same file, same gates. It is named with evidence in the PR body. The claimed file surface already covered it; nothing was added to the surface.",
        "Added packages/drivers/driver-turso/src/replica-file.testkit.ts inside the declared 'driver-turso tests' surface. Eight replica-face fixtures re-spelled from :memory: + syncUrl to a fresh local file:, because the fix refuses that pair.",
        "The PR body's 'Clause-②: no' is the claim's line verbatim; the changeset carries 'Clause-②: no (narrowing)' (see open_questions).",
        "The first gate sweep ran the three --base gates with the pinned BASE sha. I reran them exactly as printed ('--base origin/main', which equals BASE 2c1011b) and recorded those runs for --ran.",
        "The 61-command sweep outran the foreground cap and the harness moved it to the background. I waited for it in the foreground (tail --pid on the runner) and did not end the turn.",
        "Fetched pinned commit 621a4876 at depth 1 into the shared object store, as check-plugin-teardown-shape's self-test prescribes. Built the @objectstack/objectql closure under the lock for check:lean-entry-closure."
      ],
      "files_changed": [
        ".changeset/19893-turso-remote-url-replica-refusal.md",
        "packages/drivers/driver-turso/README.md",
        "packages/drivers/driver-turso/src/turso-driver.ts",
        "packages/drivers/driver-turso/src/replica-file.testkit.ts",
        "packages/drivers/driver-turso/src/turso-driver-remote-url-replica-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-driver.test.ts",
        "packages/drivers/driver-turso/src/turso-driver-ws-timeout-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-driver-supplied-client-timeout-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-driver-timeout.test.ts",
        "packages/drivers/driver-turso/src/turso-remote-autonumber-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-remote-deferred-ddl.test.ts",
        "packages/drivers/driver-turso/src/turso-remote-drift-detection-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-remote-transaction-refusal.test.ts",
        "packages/drivers/driver-turso/src/turso-transactions-unsupported-declaration.test.ts"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 19893,
      "status": "done",
      "round": "patch round 1: addendum to os-dev-report 5815469979, answering contract review 5815787919 (FAIL, changeset prose)",
      "branch": "claude/issue-19893-turso-remote-syncurl-replica",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/19971",
      "head": "7fc737470b73a61f1fb50d37315d24cf0c5f982c (fast-forward from 5fb95579; no force-push)",
      "session": "session_01Bvd69VPa6puiNzzPUroDBx (mode:subagent; the parent's harness-stamped id, as in the claim)",
      "premise_still_valid": true,
      "summary": "Prose-only patch: .changeset/19893-turso-remote-url-replica-refusal.md and packages/drivers/driver-turso/README.md, one commit, no code or test byte changed (git diff 5fb95579..7fc73747 touches 0 .ts files; turso-driver.ts blob 07363cdb at both heads). Every sentence was rewritten from the code at head: localEngineDefect fires 'remote-url' on the five lowercase prefixes in local or replica mode, and 'replica-without-file' only when the resolved mode is replica; detectMode's fallback returns 'local' whatever syncUrl says. Changeset, the seat's edits: (1) refusal bullet 3 now names a replica on a url @libsql/client reads as in-memory (:memory:, or file::memory: with or without a query string, beside syncUrl or under mode 'replica'), plus a new bullet 4: under a forced mode 'replica' only, any url that is not a local file: path; (2) a 'Not refused, unchanged here' paragraph: a url with no mode that is none of file:, :memory: or a lowercase remote scheme (uppercase LIBSQL://, a bare path) still auto-detects 'local' and runs on :memory:, with or without syncUrl, and so does the same url under a forced mode 'local'. It cites #19976 with no closing keyword; (3) the headline is narrowed to 'a local or replica TursoDriver on a remote url, or a replica off a local file, is refused at construction'. Step 5 re-read found and fixed six more false or imprecise sentences in the changeset: (a) 'a remote url' is now defined once as the lowercase schemes detectMode classifies as remote, because LIBSQL:// + syncUrl constructs; (b) 'the same fallback caught ... a replica on :memory:' was wrong, since :memory: takes toKnexConfig's own :memory: arm; (c) 'the message names the scheme' holds only for the remote-url refusal; (d) the ways-out used 'or' where both are needed (mode 'replica' + syncUrl stays refused when only one is dropped), and 'drop mode replica for a plain local database' is false for a bare path, which lands on the #19976 fall-through; (e) the blast-radius sentence 'only ... loader fixtures' omitted the stored-row redaction fixtures (spec and service-datasource) and the spec schema-parse fixture, none of which constructs the driver; (f) the headline's 'instead of silently running on a private in-memory database' is false for file::memory:?cache=shared. Measured: better-sqlite3 treats only the exact ':memory:' as in-memory and creates a file literally named ':memory:?cache=shared' in the working directory, so the headline tail is dropped and bullet 3 states it. README (4): the paragraph is now a three-item refused list; 'a replica' is qualified as auto-detected from a :memory: or file: url beside syncUrl, or forced with mode 'replica'; the remote schemes are marked lowercase; the ways out read 'drop syncUrl and any forced mode'; the syncUrl config comment 'url must be a local file:' becomes the descriptive 'the replica is the local file: named by url'.",
      "tests": "No code or test changed between 5fb95579 and 7fc73747, so round 0's readings stand for identical source bytes: driver-turso typecheck exit 0; 'Test Files 60 passed (60)', 'Tests 1358 passed (1358)'; ablation 'Tests 20 failed | 105 passed' with restore proven. Not re-run this round. New measurement this round (throwaway, scratchpad only): better-sqlite3 new Database(':memory:') leaves the cwd empty; new Database(':memory:?cache=shared') leaves a file ':memory:?cache=shared' in the cwd.",
      "gates": "At head 7fc73747 (origin/main 2c1011b01 = merge base), exactly as printed. node scripts/check-changeset-no-major.mjs --base origin/main: exit 0, '✓ This diff introduces no `major` bump.' Driven with --event carrying the seat's amended PR-body line: '✓ LEVEL AXIS: this PR declares clause-② `no (narrowing)`, and no package whose `packages/**/src/**` it moves is graded `patch`.' / 'direction arm: `narrowing` — a BREAKING change; during the launch window it ships `minor`'. node scripts/check-adr-0087-registration.mjs --base origin/main: exit 0, '✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.' with '.changeset/19893-turso-remote-url-replica-refusal.md [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)'. node scripts/check-empty-changeset.mjs --base origin/main: exit 0, '✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).' and '✓ No changeset from the merge base modified or deleted by this diff'. pnpm check:doc-authoring (named by dispatch-gates for these paths): exit 0, '✓ doc authoring guard: 403 files clean', '53 published skill files clean — no internal issue-id references', 'sibling-package prose ids hold the baseline ... no growth'. Union, re-run per os-dev.md on the new head: dispatch-gates --commands at 7fc73747 derived the same 61 commands as round 0 (sorted diff empty); --ran reconcile '61 derived, 59 run, 2 NOT-MEASURED, 0 UNRUN' (reconcile exit 0); all 59 run exit 0, including check:driver-conformance 'OK — 50 covered cell(s), 0 in the DEBT ledger, 0 exempt.' NOT MEASURED, the same two as round 0, both PREREQUISITE NOT MET because they need a whole-workspace build: pnpm check:dual-build-cjs-loads and pnpm check:type-check-debt. Before the union, the driver-turso and objectql closures were rebuilt under the lock (VERDICT command-exit 0).",
      "line_budget": "n/a — no skills/** in the diff",
      "mcp_calls": "3 this round, all reads: pull_request_read get_comments (review record 5815787919), pull_request_read get (current PR body, for the --event level reading), issue_read get_comments (read-back of this addendum). No MCP write tool.",
      "api_writes": "1 this round: comment, POST /repos/objectstack-ai/objectstack/issues/19893/comments (this addendum), through scripts/pm/with-fleet.sh --via dispatch (fleet-write relay, as objectstack-fleet[bot]; one POST /repos/objectstack-ai/objectstack/dispatches). git push x1 (fast-forward, not REST). PR body not edited.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #19976 · noted, not filed: the replica refusal's runtime message ends 'or drop `mode: 'replica'` ... for a plain local database'. For a bare path under a forced mode 'replica', dropping the mode lands on the #19976 fall-through, a Knex :memory: engine rather than a local database file. The message is code, frozen this round; the #19976 change should re-read this sentence.",
        "carrier: this PR (seat) · noted, not changed (code frozen this round): the constructor comment 'before the Knex base could open a private `:memory:` database in its place' does not hold for file::memory:?cache=shared under replica mode, where Knex would open a file literally named ':memory:?cache=shared' (measured above). The refusal itself is right for that spelling: libsql's in-memory rule, and no sync reaches the file. The turso-driver.ts header, syncUrl and mode TSDoc use 'remote url' in detectMode's lowercase sense, which the localEngineDefect docblock defines.",
        "carrier: this PR (seat) · noted, not edited (the PR body is the seat's): the PR body still reads 'Verification, HEAD `5fb95579`'. The code is byte-identical at 7fc73747, and the union was re-run there with the same result. The body's 'The message names the scheme it met and both ways out: drop `syncUrl` (or the forced `mode`)' carries the same two imprecisions this round fixed in the changeset (the replica-arm message names no scheme; 'or' fails for mode 'replica' + syncUrl). The amended body as read back ends with no attribution footer; that is state another actor set, and I did not touch it."
      ],
      "deviations": [
        "README step 4 wording: the seat's text says 'auto-detected from `file:`'; I wrote 'auto-detected from a `:memory:` or `file:` url beside `syncUrl`'. detectMode returns replica for `:memory:` + syncUrl too, so 'from `file:`' alone would be false for the in-memory case that the list item names.",
        "Headline step 3: narrowed as asked, and the tail 'instead of silently running on a private in-memory database' was dropped because it is false for file::memory:?cache=shared (measured).",
        "Step 7: beyond the four named gates I re-ran the full 61-command union at 7fc73747, because os-dev.md requires a union re-run on any new head and wins on conflict. That meant rebuilding the driver-turso and objectql closures in the recreated worktree under the lock first.",
        "The level-axis --event reading used the round-0 body with its Clause-② line replaced by the seat's amended line 'Clause-②: no (narrowing)'. That line is the only one the gate reads, and it matches the current PR body read back via MCP."
      ],
      "files_changed": [
        ".changeset/19893-turso-remote-url-replica-refusal.md",
        "packages/drivers/driver-turso/README.md"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #19971 at 7fc73747

    domain:engine#1, session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-24T14:51Z. Reviewed against references/review-checklist.md, on GitHub rather than the dev's report (os-dev-report 5815469979 plus its patch-round addendum on this card).

    Landing: ready + auto-merge through the queue. #19894 (serial, same file) unlocks when this lands.


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #19971, verified on main

    domain:engine#1, session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-24T15:23Z.


    Generated by Claude Code

  7. added 3 commits that reference this issue on Sep 28, 2026
    0142415
    61609ed
    2491729
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:enginepriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions