Repository navigation
Commit fdbcec0
fix(cli): six read-only arms claim no row or table, and name the journal-mode switch on a SQLite file (#23725)
Fixes #23622
Clause-②: no
The remainder of #23562, with PR #23608's pattern. Six commands boot
through the SQL driver's connect before they print. On a SQLite file
still on a rollback journal, that connect switches the journal mode,
which rewrites the file header and no row. Their sentences said "writes
nothing", "nothing was written" or "Nothing was changed". Each now
claims no row or table, and on a SQLite target it is followed by the
exported `JOURNAL_MODE_SWITCH_NOTE`: "Opening a SQLite file can still
switch its journal mode (to WAL by default), which changes its header
only." The basis for `Clause-②: no` is in the claim: this is operator
text only. No flag, exit code, accepted input, `--json` document or
export moves, and there is no `packages/spec` edit.
## The premise, measured per command (H1)
I ran the real CLI (`bin/run-dev.js`) on one served-shape fixture. A
full boot created every table these commands read, and one row of work
was seeded for each. The file was then put on `journal_mode = delete`,
and each run got its own copy. Bytes 18 and 19 of the header are the
journal mode (1,1 means a rollback journal; 2,2 means WAL), and bytes 24
to 27 are the change counter. "Rows" means the schema plus every row of
every table, read on a connection of my own.
| Run | Header 18,19 · counter | Rows |
|---|---|---|
| `os migrate security-catalog-overlays`, beside an idle holder process
| 1,1 · 4 → 2,2 · 5 | unchanged |
| `os migrate recorded-by` (dry run, one sentinel row) | 1,1 · 4 → 2,2 ·
5 | unchanged |
| `os migrate resume` (list, one interrupted run) | 1,1 · 4 → 2,2 · 5 |
unchanged |
| `os secret orphans` (report) | 1,1 · 4 → 2,2 · 5 | unchanged |
| `os secret rewrap` (dry run) | 1,1 · 4 → 2,2 · 5 | unchanged |
| `os storage orphans` | 1,1 · 4 → 2,2 · 5 | unchanged |
| `os secret orphans --delete`, declined at the prompt (under a pty) |
1,1 · 5 → 2,2 · 6 | unchanged |
| the same run, with `sys_setting` dropped first | 1,1 · 6 → 2,2 · 8 |
`sys_setting` re-created by the plain boot |
| `os migrate recorded-by --apply`, declined | 1,1 · 4 → 2,2 · 5 |
unchanged |
| `os migrate resume --run run_23622`, declined | 1,1 · 4 → 2,2 · 5 |
unchanged |
| `os secret rewrap --apply` (its prompt was not reached: every row was
"left") | 1,1 · 5 → 2,2 · 6 | unchanged |
The before runs were at `4c21e57169` and the after runs at `585275807`.
Both measured the same header movement. Only the printed lines differ.
H2 holds by reading: `recorded-by` and `resume` probe no occupancy, and
they print their line on every dialect. So the base sentence is
corrected on every dialect, and the note is added only when the boot's
primary datasource is a SQLite file.
## The texts
| # | Where | FROM | TO |
|---|---|---|---|
| 1 | `migrate/security-catalog-overlays.ts:198` | "The preview below
writes nothing." | "The preview below writes no row or table." plus the
note. It prints only on a busy SQLite file, so the note is always there
|
| 2 | `migrate/recorded-by.ts:158` | "Nothing was changed. Re-run with
--apply to rewrite them to NULL." | "No row or table was changed. Re-run
with --apply to rewrite them to NULL." plus the note on SQLite |
| 3 | `migrate/resume.ts:172` | "Nothing was changed. Re-run with --run
ID to act on one." | "No row or table was changed. Re-run with --run ID
to act on one." plus the note on SQLite |
| 4 | `secret/orphans.ts:332` | "Report only — nothing was written or
deleted." | "Report only — no row or table was written or deleted." plus
the note on SQLite, before the elapsed time |
| 5 | `secret/rewrap.ts:316` | "Dry run — nothing was written." | "Dry
run — no row or table was written." plus the note on SQLite, before the
elapsed time |
| 6 | `storage/orphans.ts:61` (help) | "… Writes nothing, tombstones
nothing, deletes nothing." | "… Writes no row or table, tombstones
nothing, deletes nothing." Help text carries no note |
| 7 | `migrate/plan.ts:210` (a comment) | "a plan writes nothing" | "a
plan writes no row or table" |
| 8 | `secret/orphans.ts:372` (`--delete` declined) | "Aborted — nothing
was written or deleted." | "Aborted — no export was written and no row
was deleted." plus the note on SQLite |
In row 3, ID stands for the placeholder the command prints, `id` inside
angle brackets.
**Row 8 claims no row, not "no row or table".** Its boot is the plain
write-mode boot, which performs schema sync. With `sys_setting` dropped,
that boot re-created the table before the prompt, and the old line still
said "nothing was written". The new line names the export and the rows,
which is what the prompt guards.
**Folded in under the bounded in-place rule**, all in files on this
claim's surface. Each is the same sentence on the same mechanism,
mechanical, in the same gate family, and measured:
- the same declined-prompt line after a plain boot:
`migrate/recorded-by.ts:179` and `migrate/resume.ts:218` ("Aborted —
nothing changed." becomes "Aborted — no row was changed.", plus the note
on SQLite, measured above), and `secret/rewrap.ts:294` ("Aborted —
nothing was opened or written." becomes "Aborted — no row was opened or
written.", plus the note on SQLite; its boot was measured, and its line
is pinned against a replaced boot);
- the help and flag descriptions of the read-only default modes, the
same class as row 6: `secret/orphans.ts:98` and `:115`, and
`secret/rewrap.ts:69` and `:85` ("writes nothing" becomes "writes no row
or table").
`security-catalog-overlays.ts:222` ("Aborted — nothing deleted.") is
kept. It prints before that command boots, so it is true as written.
**The SQLite test.** Rows 2 to 5 and the declined lines ask the booted
stack: `describeDriverSqliteFile(stack.driver?.config) !== undefined`.
This is the existing `utils/connection-display.ts` helper, read and not
edited. `SqlDriver` keeps the declared target in `config`, even where a
read-only boot opened an absent file as `:memory:`, so this test gives
the same answer as PR #23608's `occupancy.status !== 'not_applicable'`
for the ceremony. PostgreSQL and MySQL answer `undefined`.
`utils/sqlite-occupancy.ts` is read, not edited.
## Pins (one per printed text)
- **Real rollback-journal file:**
`secret/orphans.journal-mode.integration.test.ts`. It reads the header
(1,1 → 2,2), checks that schema and rows are unchanged, and checks the
corrected line and the note. It is where the SQLite test meets a real
driver config. The oclif config is loaded in `beforeAll`, so the case
itself runs in 1.73 s.
- **Printed line, with the boot replaced** (a SQLite config gets the
note; a PostgreSQL config gets the base sentence and no note):
`migrate/recorded-by.test.ts` and the new `migrate/resume.test.ts` (dry
run or list, and the declined prompt); `secret/orphans.guards.test.ts`
and `secret/rewrap.guards.test.ts` (report or dry run, the declined
prompt, and help and flag text); the new
`migrate/security-catalog-overlays.preview-note.test.ts` (a busy probe);
the new `storage/orphans.test.ts` (help).
- `migrate/data-commands.absent-database.integration.test.ts`: its two
`humanEmpty` regexes now read the corrected sentences.
**Ablation**, at `7fe367ec7`, through `scripts/ablation-replace.mjs`,
with an EXIT/INT/TERM trap. No rebuild was needed: the subject is the
CLI's own `src`, reached by relative imports. I put back the old
`secret/orphans.ts` report line (blob `cc1721741181` → `71acbbdcf46c`,
anchor count 1 → 0). Result: 3 failed, 13 passed. The SQLite and
PostgreSQL guards cases went red, receiving "Report only — nothing was
written or deleted.", and so did the real-file case, after its header
assertion had passed. Restore: the blob equals HEAD (`cc1721741181`) and
`git diff HEAD` is empty. The direction was red, as expected.
## Verification (head `dbaa3358a`)
- `@objectstack/cli` build and `typecheck` (`tsc --noEmit` plus
`check:test-typecheck`, held at 3 files, 28 errors and 6 signatures):
exit 0. `tsc --listFiles` puts all 8 touched test files in the 1578-file
program.
- CLI unit project (`vitest run --project unit --maxWorkers=2`): Test
Files 295 passed (295), Tests 4362 passed (4362), VERDICT command-exit
0. That run was at `1a2c2aa63`. The two unit files changed since then
were re-run by path at `dbaa3358a`: 2 files, 10 tests passed.
- Integration files this diff touches, run by path:
`data-commands.absent-database`, both guards files and the real-file
pin. Test Files 4 passed (4), Tests 66 passed (66), VERDICT 0. The rest
of the integration layer is declared to CI.
- `eslint packages/cli --no-inline-config`: exit 0, 696 files, 0 errors,
0 warnings.
- `dispatch-gates --commands --repo objectstack-ai/objectstack` derived
64 families at `dbaa3358a` (16 paths, 862 lines). All 64 ran there, with
each exit code captured before any pipe: all exited 0. `--ran` printed
"64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN", a derived zero from 64
recorded exit codes. Among them, `check-empty-changeset --base
origin/main` printed "No empty-frontmatter changeset introduced by this
diff (1 declaring changeset(s) added)". This PR adds a changeset and
edits none, so the designed red PR #23608 met does not arise. Two first
runs, at `1a2c2aa63`, were red because of my new doubles:
`check:engine-double-contract` (write methods without the dispatch
predicate) and `check:objectql-double-limit` (a find that ignored the
caller's limit). `dbaa3358a` fixed both: the doubles now only read.
`check:dual-build-cjs-loads` and `check:i18n-coverage` first exited 3
because build output was missing. After a build of the packages they
read, both exit 0. The repo-wide `pnpm lint` is CI's.
## Acceptance notes
- **The same false sentence, outside this claim's file surface**,
measured on the same runs. I left these alone and named them for the
seat as this family's remainder:
- `os storage orphans` still prints "This pass is READ-ONLY: nothing was
written, tombstoned or deleted." That line comes from
`services/service-storage/src/stranded-orphan-inventory.ts:413`.
- `os secret rewrap`'s dry run still prints "Dry run: every attributed
row was opened, re-sealed and verified in memory, and nothing was
written." That is `REWRAP_NOTES.dryRun` in
`cli/src/utils/sys-secret-rewrap.ts:504`, which is in `--json` too.
- `os migrate summary-nulls`' dry run still prints "Dry run — nothing
was written. Re-run with --apply to backfill." That line comes from
`objectql/src/summary-backfill.ts:534`. #23562's dev measured this
boot's switch.
- **Developer comments not changed** (not operator text; the ruling
named only `plan.ts:210`): `recorded-by.ts:62` ("… and writes nothing"),
`secret/rewrap.ts:44` ("… and writes nothing"), and
`secret/orphans.ts:221` ("this report promises to write nothing", about
key material).
- **Design, not a finding:** a write-mode boot (`--apply`, `--run`,
`--delete`) runs schema sync before its prompt, so a declined run can
leave a table it created. The sentences now claim only rows.
- **No merge of `origin/main` before opening.** The two commits since
the base (`c03077e29`, `9e0945cf4`) touch the runtime sandbox and
metadata-protocol draft saves. They touch nothing in `cli`, the boot or
the drivers. This is a declared narrowing; CI's merge-ref run covers the
joint tree.
Built by `session_01FLwgbTSmGMrqsXkBDsiwfG`, the dev for `domain:cli`
seat 1's claim `6200653126`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FLwgbTSmGMrqsXkBDsiwfG)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6ee483c commit fdbcec0
16 files changed
Lines changed: 839 additions & 21 deletions
File tree
- .changeset
- packages/cli/src/commands
- migrate
- secret
- storage
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
503 | 503 | | |
504 | 504 | | |
505 | 505 | | |
506 | | - | |
| 506 | + | |
507 | 507 | | |
508 | 508 | | |
509 | 509 | | |
| |||
516 | 516 | | |
517 | 517 | | |
518 | 518 | | |
519 | | - | |
| 519 | + | |
520 | 520 | | |
521 | 521 | | |
522 | 522 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
207 | 207 | | |
208 | 208 | | |
209 | 209 | | |
210 | | - | |
| 210 | + | |
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
11 | 17 | | |
12 | 18 | | |
13 | | - | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
14 | 22 | | |
| 23 | + | |
15 | 24 | | |
16 | 25 | | |
17 | 26 | | |
18 | 27 | | |
19 | 28 | | |
20 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
21 | 48 | | |
22 | 49 | | |
23 | 50 | | |
| |||
41 | 68 | | |
42 | 69 | | |
43 | 70 | | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| |||
116 | 118 | | |
117 | 119 | | |
118 | 120 | | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
119 | 132 | | |
120 | 133 | | |
121 | 134 | | |
| |||
155 | 168 | | |
156 | 169 | | |
157 | 170 | | |
158 | | - | |
| 171 | + | |
159 | 172 | | |
160 | 173 | | |
161 | 174 | | |
| |||
176 | 189 | | |
177 | 190 | | |
178 | 191 | | |
179 | | - | |
| 192 | + | |
180 | 193 | | |
181 | 194 | | |
182 | 195 | | |
| |||
0 commit comments