Skip to content

fix(driver-memory): persistence opt-in again + move the remaining suites to in-memory SQLite (#4065) - #4100

Merged
os-zhuang merged 6 commits into
mainfrom
claude/inmemory-to-sqlite-memory-5f7n9e
Jul 30, 2026
Merged

fix(driver-memory): persistence opt-in again + move the remaining suites to in-memory SQLite (#4065)#4100
os-zhuang merged 6 commits into
mainfrom
claude/inmemory-to-sqlite-memory-5f7n9e

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes #4065.

保留 @objectstack/driver-memory(不删包),但把它退回文档里早已写明的角色,并停止在测试与脚手架里依赖它。

⚠️#4083 重叠 —— 需要你确认一处

本分支开着的时候,main 上落了 #4083#4111 + #4108,处理的是同一个隐患。冲突已全部按「main 优先」解决,其工作原样保留

  • default-datasource-driver-factory.ts —— 整取 main。它的 buildMemoryConfig/scopeMemoryPersistence 会把已请求的持久化模式展开成 per-datasource 目的地,我的版本没有;我的丢弃。
  • sqlite-driver-fallback.ts —— 整取 main 的无条件 persistence: false。我原来让它跟随所替代的 sqlite 目标(file → 'file'),那会把 datasource-autoconnect 的联邦查询测试在本地必现失败:ext_note 读到 6~12 行而非 2 行(CI 绿,需第二台机器复核) #4083 刚修掉的进程级共享文件别名问题重新引入。
  • datasource-autoconnect.test.ts —— 整取 main,回退本分支把该文件迁到 wasm SQLite 的改动。main 在那里加了「内存池不留痕」的回归测试;跑在 SQLite 池上它会空洞地通过(这种池根本不写 .objectstack/)。该文件留在 memory driver 上,继续守它被写出来要守的东西。

本分支存活下来的,是 #4083 刻意留下的另一半:driver 自身的默认值。 #4111 修了工厂路径,#4108 明确写进文档:直接构造的 new InMemoryDriver() 仍保持 'auto',仍会相对 CWD 写 .objectstack/data/memory-driver.json。而 #815 的验收需求第 1 条说那个默认值从来就不是被接受的设计——所以这里把它改成 false

两者互补:#4083 的 scoping 仍是唯一能阻止两个已选择持久化的池共用一个文件的机制,其显式 false 变成双保险。

需要你点头的是:这与 #4108 刚写进文档的说法相反(那句已在本 PR 中一并更新)。如果你当时是有意保留 'auto',说一声我就把 P0 撤掉,只留 P1/P2。

关键发现:'auto' 默认值是实现偏离,不是产品决策

#4065 判断「改默认是破坏性的(#815 的 dev/UED 诉求依赖它)」。核对 #815 的验收需求后,这句不成立:

1. 统一持久化入口: … 默认情况下不启用持久化(纯内存,行为不变)。

5. 配置示例: // 纯内存new InMemoryDriver()

#815 明确要求持久化 opt-in,并把 new InMemoryDriver() 标注为纯内存。今天的 'auto'(Node.js 下 = 落盘)是从这份已验收设计上漂移出来的。

漂移能存活的原因不是「没有测试」:MemoryConfigSchema 确实钉住了默认值,断言的是 'auto';driver 也实现 'auto';两边一致,看起来已验证。没人核对的是「一致的那个值是不是 #815 定的那个」。driver 自己的 persistence.test.ts 也抓不到——每个用例都显式传 persistence,省略路径从未被覆盖。

改了什么

P0 — 默认值(82b161f,经合并后收敛)

P1 — 测试迁移(a7e932f

9 个测试文件从 mingo 换到 SqliteWasmDriver({ filename: ':memory:' }),与 bootStack 一致(纯 JS 无原生编译,CI 安全;真 SQL 语义)。迁移暴露的每一处失败都是 memory driver 一直在吸收的 fixture 缺陷:

症状 真因
REST 返回 404 OBJECT_NOT_FOUND bootstrap 之后注册的对象错过建表同步;SQL 首写 no such table,被 REST 错误映射成 404 —— 路由形状的症状,DDL 形状的病因
sys_notification 写入失败 MessagingServicePlugin 写它但不声明它(那是 platform object),精简 kernel 没加载 platform-objects。mingo 首次触碰自动建表,把这个遗漏完全盖住
驱动未连接 memory 不需要 connect(),SQL 需要

刻意不动的read-coercion-conformance 保留双 driver 矩阵;以及主体就是 memory driver 或其接线的套件(standalone-stackmemory://sqlite-driver-fallback、CLI driver 标签测试、driver-memory 自身套件),外加合并后新增的 datasource-autoconnect

初版分析里我建议把 memory 加回 date-bucket / empty-group parity 网关。按「暂时不需要使用和维护」的意图这条已撤回。

P2 — 脚手架与文档(988910a

e6c2adb 类 docstring 的 "production-ready" 去掉。它不存储任何约束(create() 就是 table.push(),无主键/唯一/NOT NULL/外键/列类型),bulkCreate 会落两行同 id —— #4065 的第二个发现。按 Prime Directive #10,driver 转维护态就裁掉声明。

e7d31c6)收尾 cwd 写副作用 —— 追这个残留挖出两个真问题:

  1. projectRoot 只管了一半的栈。 createStandaloneStackprojectRoot 文档说是把 boot 的落盘状态限定在项目目录,它也确实重定向了默认 sqlite 库——但从未传给 MetadataPlugin,其 FileSystemRepository 仍以 process.cwd() 为根。于是同一个「项目根」指向两个目录。现已转发 rootDirbootSchemaStack 也接受 projectRoot

  2. CLI 把自己的测试编译进了 dist/,而 vitest 会去跑它们。 tsconfig.build.json 收录整个 src 且无 exclude,于是每个 src/**/*.test.ts 都产出 dist/**/*.test.jsfiles: ["dist"] 把它们发布了出去;本包没有 vitest 配置,vitest run 会把编译副本和源码一起收集——81 个测试文件 / 849 个用例,而源码只有 58 / 581

    这会静默地让改动失效:对源码测试的修复看起来「没生效」,因为跑的仍是修复前的编译副本。它同样允许源码测试被改成通过、而陈旧副本继续断言旧行为。现已在构建中排除测试文件。其他包不受影响(用 tsup,只产出声明的入口;已扫描确认只有 CLI 命中)。

验证

一处保留(by design,非残留)

showcase_external.db。这是 showcase 外部 datasource 声明按设计写的相对路径,fixture 播种有 count === 0 守卫、幂等、已 gitignore —— 与 memory-driver.json 每跑一次累加 2N 行不是同一类。写在 examples/app-showcase/ 自己项目目录里是正确的;dogfood 目录下那份是因为 dogfood 从自己的包目录引导 showcase app。要消除后者只能改 example app 的声明契约、加测试专用 env 开关、或重构 dogfood 的 cwd —— 都比一个幂等的 gitignored 小文件代价大,故未动。

claude added 4 commits July 30, 2026 09:10
…yDriver is pure in-memory (#4065)

`InMemoryDriverConfig.persistence` defaulted to `'auto'`, and on Node.js
`'auto'` resolves to FILE persistence. So `new InMemoryDriver()` — the shape
every caller in this repo uses — silently wrote
`.objectstack/data/memory-driver.json` into the process CWD and reloaded it on
the next boot. The default is now `false`.

This restores the design #815 accepted rather than replacing it: its
requirement #1 reads "默认情况下不启用持久化(纯内存,行为不变)", and its own
config examples list `new InMemoryDriver()` under "纯内存". `'auto'` was drift.

Symptom: `datasource-autoconnect.test.ts` seeds two rows with fixed ids and
asserts the exact set. Run 1 passed and wrote them to disk; run 2 loaded them
back, appended two more and failed with four; run N had 2N. CI never saw it —
every job is a fresh clone, so every CI run is run 1 — but `pnpm test` twice in
one working tree could only ever go green once.

What let the drift survive is not "there was no test". `MemoryConfigSchema`
pinned the default and asserted `'auto'`; the driver honoured `'auto'`; the pair
agreed and looked verified. Nothing checked that the agreed value was #815's.
The driver's own persistence tests could not have caught it either — every case
passed `persistence` explicitly, leaving the omitted-value path untested.

Both sides are now covered: three behavioural tests (no CWD write, no
cross-instance row carry-over, opt-in still persists) plus the flipped schema
assertion. Verified they fail against the old default before landing the fix.

Hosts that genuinely want durability now say so instead of inheriting it:

- `resolveSqliteDriver`'s last-resort rung mirrors the sqlite target it stands
  in for — `persistence: 'file'` for a file database, `false` for `:memory:` —
  so a dev whose native and wasm SQLite both failed keeps the durability they
  would have had.
- `createDefaultDatasourceDriverFactory`'s `memory` branch is ephemeral unless
  the datasource DEFINITION declares `config.persistence` (Prime Directive #12:
  a contract-level knob, not a silent host default).
- `DevPlugin`'s driver is explicitly `persistence: false`, matching the cache,
  queue, job, i18n, storage and search stubs it ships beside — it was the one
  piece of that stack that quietly outlived the process.

Also stops this suite writing into its own package dir: the shorthand
`'file'`/`'auto'` cases take the adapter's default RELATIVE path, so they now
run inside a scratch CWD.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
…ry SQLite (#4065)

Ten test files used `InMemoryDriver` as a convenience backing store — somewhere
for rows to go while the suite proved something else (REST routing, datasource
auto-connect, the batch `$ref` contract, metadata history). They now run on
`SqliteWasmDriver` at `:memory:`, the engine `@objectstack/verify`'s `bootStack`
already gives the dogfood gate: pure JS (no native build, CI-safe) and real SQL.

The point is fidelity, not tidiness. Production runs SQL, and mingo differs from
it in ways that let a suite pass while the behaviour it stands for is broken.
Every failure this migration produced was a fixture defect the memory driver had
been absorbing:

- Tables were never created. `create()` on the memory driver is a bare
  `table.push()` onto an auto-vivified array, so an object registered AFTER
  `kernel.bootstrap()` — which misses the boot-time schema sync — looked fine.
  On SQL the first write fails with `no such table`, which the REST error mapper
  turns into a 404 OBJECT_NOT_FOUND: a routing-shaped symptom for a DDL-shaped
  cause. Four suites needed an explicit `syncObjectSchema`; the
  `schemaMode: 'external'` datasource in datasource-autoconnect needed an
  `initObjects` standing in for the DDL that already ran on the remote side —
  the step a real external datasource genuinely requires.
- A missing object declaration read as working. notifications.hono.integration
  writes `sys_notification`, which MessagingServicePlugin does not declare (it
  is a platform object, and that lean kernel never boots platform-objects).
  Auto-vivification hid it. The suite now registers the REAL SysNotification
  rather than a hand-copied stand-in, keeping one schema (Prime Directive #12).
- `connect()` was optional. The memory driver needs none; a SQL driver does.

Deliberately NOT moved: read-coercion-conformance keeps its two-driver matrix
(proving a stored value reads back as its declared type on BOTH engines is the
point of that gate), and the suites whose subject IS the memory driver or its
wiring — standalone-stack (`memory://`), sqlite-driver-fallback (the dev
step-down), the CLI driver-label tests, and driver-memory's own suite.

No new coverage is claimed: each suite asserts exactly what it did before,
against a more faithful store. 2,375 tests green across the eight affected
packages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
…#4065)

`os init` and the `create-objectstack` blank template both listed
`@objectstack/driver-memory` in the generated `dependencies`. It was the only
driver named, which read as an endorsement — "this is the driver your app runs
on" — when it is the LAST-RESORT rung of the dev step-down (native
better-sqlite3 → WASM SQLite → mingo). A new project's first impression of the
data layer should not be the engine that enforces no primary keys, no
uniqueness, no NOT NULL and no column types.

It was also redundant: `@objectstack/runtime` already depends on driver-sql,
driver-sqlite-wasm and driver-memory, and every script in both scaffolds runs
through the CLI, which carries all four. Removing the line changes nothing a
generated project can do — `objectstack dev` still resolves SQLite by default
and OS_DATABASE_URL still selects Postgres / MySQL / MongoDB.

Docs updated to match:

- *Your first project*'s package table dropped its driver row and now says where
  drivers actually come from.
- *Database Drivers* § Memory Driver claimed "Data is lost when the process
  exits" — false while `'auto'` was the default, which wrote a file into the
  working directory. It now documents the opt-in persistence default, carries a
  migration callout for callers who relied on the old behaviour, and points test
  authors at in-memory SQLite with the reason (mingo enforces no constraints, so
  a green run against it is weaker evidence than it looks).

The Vercel deployment snippet is left as-is: it builds an InMemoryDriver
deliberately to stay self-contained and already warns that serverless loses all
data on cold start — still accurate, and now true by construction rather than by
the serverless detection in `'auto'`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
…does not enforce (#4065)

The class docstring opened with "A production-ready implementation of the
ObjectStack Driver Protocol". The driver stores no constraints of any kind:
`create()` is a `table.push()` and `syncSchema()` only allocates an array and
indexes temporal fields, so there is no primary key, no uniqueness, no NOT NULL,
no foreign key and no column typing. `bulkCreate` lands two rows with the same
id where a SQL driver raises a constraint violation, and a read returns both —
the second finding in #4065, and the mechanism behind the 2N row growth there.

Per Prime Directive #10 the options for `declared ≠ enforced` are implement it,
trim the claim, or file it. With this driver moving to maintenance-only — kept
for the last-resort rung of the dev step-down, browser/edge runtimes with no
SQLite build, and the read-coercion parity gate — the claim is what goes.

The docstring now states the missing constraints plainly, names the driver as a
WEAK oracle for tests, and points at in-memory SQLite instead. No behaviour
change; 197 driver-memory tests unchanged and green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 11:33am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file protocol:data tests tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 10 package(s): @objectstack/cli, @objectstack/client, create-objectstack, @objectstack/metadata, @objectstack/driver-memory, @objectstack/plugin-dev, packages/qa, @objectstack/runtime, packages/services, @objectstack/spec.

125 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via packages/cli, packages/client, create-objectstack, @objectstack/spec)
  • content/docs/ai/skills.mdx (via create-objectstack, @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/client, packages/runtime, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli, @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/client, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @objectstack/client, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via packages/services, @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/driver-memory, @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli, create-objectstack)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/driver-memory, @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/glossary.mdx (via @objectstack/driver-memory)
  • content/docs/getting-started/index.mdx (via create-objectstack)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli, @objectstack/client, create-objectstack, @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via packages/metadata, @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli, packages/client)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, packages/client, packages/services, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/driver-memory, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli, @objectstack/client, @objectstack/driver-memory, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/qa, packages/runtime, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/driver-memory, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @objectstack/client, create-objectstack, @objectstack/metadata, @objectstack/driver-memory, @objectstack/plugin-dev, @objectstack/runtime, packages/services, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/services, @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/metadata)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli, @objectstack/client)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/driver-memory, @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/client, @objectstack/driver-memory, @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v15.mdx (via create-objectstack)
  • content/docs/releases/v16.mdx (via @objectstack/cli, @objectstack/client, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via create-objectstack, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

claude added 2 commits July 30, 2026 11:06
…ling tests into dist (#4065)

Two defects behind the last stray `.objectstack/` directory — the one under
`packages/cli/`. Neither turned out to be cosmetic.

1. `projectRoot` only got half the stack. `createStandaloneStack`'s
   `projectRoot` is documented as scoping a boot's on-disk state to the project
   folder, and it did redirect the default sqlite database — but it was never
   passed to MetadataPlugin, whose FileSystemRepository kept rooting at
   `process.cwd()`. One "project root" therefore meant two directories: a boot
   pointed at project A wrote `A/.objectstack/data/` and
   `<cwd>/.objectstack/metadata/`. It now forwards `rootDir`, and
   `bootSchemaStack` takes a `projectRoot` to pass down (default `process.cwd()`
   — right for every real `os migrate`, which runs from the project dir). The
   two migrate integration suites now scope their boots to the tempdir fixture
   they already build.

2. The CLI compiled its own tests into dist — and vitest ran them.
   `tsconfig.build.json` included all of `src` with no exclude, so every
   `src/**/*.test.ts` was emitted as `dist/**/*.test.js`. `files: ["dist"]`
   published them, and — this package has no vitest config — `vitest run`
   collected the compiled copies alongside the sources: 81 test files / 849
   tests where the sources hold 58 / 581.

   That silently defeats edits. A fix to a source test appeared not to work
   because the run was still executing the pre-fix compiled duplicate; that is
   how this residue survived a correct fix long enough to look like a different
   bug. It also lets a source test be edited to pass while its stale twin keeps
   asserting the old behaviour, with neither obviously wrong. Tests are now
   excluded from the build.

No other package is affected — the rest build with tsup, which emits only
declared entry points. Verified by scanning every packages/*/dist for
`*.test.js`; the CLI was the only hit.

Verified: full forced suite INCLUDING dogfood green (132/132 tasks), CLI suite
run twice back-to-back leaves no `.objectstack` behind, lint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
main landed #4083 (#4111 + #4108) on the same hazard while this branch was open.
That work is kept; conflicts resolved in its favour wherever it overlapped:

- `default-datasource-driver-factory.ts` — took main's wholesale. Its
  `buildMemoryConfig`/`scopeMemoryPersistence` expand a REQUESTED persistence
  mode into a per-datasource destination, which mine did not do; mine is dropped.
- `sqlite-driver-fallback.ts` — took main's unconditional `persistence: false`.
  Mine mirrored the sqlite target it stands in for (file → `'file'`), which would
  have reintroduced exactly the process-global shared-file aliasing #4083 fixed.
- `datasource-autoconnect.test.ts` — took main's wholesale, reverting this
  branch's migration of that file to wasm SQLite. Main added a regression test
  there for the memory pool leaving nothing behind; on a SQLite pool it would
  pass vacuously, since such a pool never writes `.objectstack/` at all. The file
  stays on the memory driver and keeps guarding what it was written to guard.

What survives from this branch is the half #4083 deliberately left open: the
DRIVER's own default. #4111 fixed the factory path and #4108 documented that a
directly-constructed `new InMemoryDriver()` keeps `'auto'` and still writes
`.objectstack/data/memory-driver.json` relative to the CWD. #815's requirement #1
("默认情况下不启用持久化(纯内存,行为不变)") says that default was never the
accepted design, so it goes to `false` here. The two compose: #4083's scoping
remains the only thing that stops two OPTED-IN pools aliasing one file, and its
explicit `false` becomes belt-and-braces.

Comments asserting `'auto'` is the current default are corrected to past tense in
the three places main wrote them, so the tree does not contradict itself, and the
`drivers.mdx` build-path table and both changesets are reconciled the same way.

Verified after the merge: full forced suite INCLUDING dogfood green (132/132),
lint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5q3BZMpdiAueHf2emhDY9
@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 12:53
@os-zhuang
os-zhuang merged commit 7309c81 into main Jul 30, 2026
29 of 30 checks passed
@os-zhuang
os-zhuang deleted the claude/inmemory-to-sqlite-memory-5f7n9e branch July 30, 2026 12:53
os-zhuang added a commit that referenced this pull request Jul 30, 2026
…-dist guard (#4156)

Three CI changes, all lessons #4065 taught the hard way. CI configuration only.

1. Nightly rerun-safety gate. Every job in this repo runs on a fresh clone,
   which makes CI structurally incapable of seeing a suite that pollutes its own
   working tree and therefore passes exactly once — CI always runs pass #1, so
   it is always green. #4065 sat in the repo through every CI run it ever had
   and surfaced only because somebody ran the full suite twice in one checkout
   while doing unrelated work, where it looked like THEIR change had broken
   something. The new job runs the full suite twice in one tree with `--force`
   (turbo would otherwise replay the cache and report green without executing
   anything) and fails if pass 2 disagrees with pass 1.

2. `timeout-minutes` on all eight ci.yml jobs. There were none, so every job
   inherited GitHub's 6-hour default — and a job stuck that way reads as "still
   running" rather than broken, the worst failure mode a gate can have.

3. A build-output guard against compiled test files. A package built with plain
   `tsc` that does not exclude tests emits `dist/**/*.test.js`: `files: ["dist"]`
   publishes them, and a package with no vitest config COLLECTS them alongside
   its sources, so every `src/**/*.test.ts` also runs as a stale duplicate frozen
   at the last build. That silently defeats edits. @objectstack/cli shipped
   exactly that (81 test files / 849 tests where its sources hold 58 / 581) until
   #4065. Everything else builds with tsup, so this gate exists to stop the NEXT
   tsc-built package repeating it.

Follow-up to #4100. Related: #4154.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation protocol:data size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

本地 pnpm test 只能跑绿一次:InMemoryDriver 默认把数据落盘,datasource-autoconnect 测试在第二次运行必然失败

2 participants