fix(dev-dx): hot-reload new objects end to end, persistent dev-admin hint, doctor container/nav refs#3108
Merged
Merged
Conversation
…hint, doctor container/nav refs
Three P2s from the 15.1 third-party evaluation, all reproduced against a
real create-objectstack scaffold and re-verified fixed on the same
project with this branch's runtime.
1. Hot-added objects (os dev watch) were dead until restart. The
artifact reload path calls MetadataManager.register(), which fires no
subscribe() watchers — ObjectQL's registry bridge never saw the new
object, tables only ever came from the boot-time sync, and seeds only
from the boot-time bundle. Now:
- metadata: the metadata:reloaded payload carries the freshly parsed
artifact collections (seeds have no name and never enter the
manager — the payload is the only channel)
- objectql: the reload hook ingests payload object definitions into
the SchemaRegistry (mirroring the subscribe handler, provenance
preserved) and re-runs the idempotent schema sync, serialized,
honoring skipSchemaSync
- runtime: a dev-gated, single-tenant hot-reload seeder loads seeds
for first-seen objects only — an already-loaded (possibly
user-edited) dataset is never re-upserted mid-run
- cli: the watch recompile line calls out new objects explicitly
2. Dev admin credentials vanished after the first boot. os dev uses a
persistent DB, so the seed (and the banner hint keyed off it) only
fired on the seeding boot, and the login page had no signal at all.
maybeSeedDevAdmin now re-arms the hint whenever the seed account
still verifies against the default password (better-auth native
password.verify), and getPublicConfig() exposes a dev-only
devSeedAdmin field for the Console login page (objectui side ships
separately). Hint disappears the boot after the password changes —
verified live in all three states.
3. os doctor reported objects bound via defineView containers
(list/listViews/form/formViews data.object, subform childObject,
lookup form fields) and app navigation (objectName, nested children,
areas) as 'defined but not referenced'. The collector now walks the
canonical shapes plus flow node config.object/objectName; the dead
agent.objects read is gone and findOrphanViews descends into
containers. Stock CLI on the probe project flags 3/3 objects; patched
flags only the genuinely unreferenced one.
Tests: cli 524, plugin-auth 460, objectql 905, runtime 544,
metadata 260 — all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 5 package(s): 40 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Jul 17, 2026
os-zhuang
added a commit
that referenced
this pull request
Jul 17, 2026
…rs (#3112) (#3131) * fix(metadata): register()/unregister() announce to subscribe() watchers (#3112) `MetadataManager.register()` updated the in-memory registry, persisted to writable loaders and published to the realtime service — but never called `notifyWatchers()`. `unregister()` had the same gap. Watchers only ever fired from the `saveMetaItem` path (indirectly, via the sys_metadata repository watch stream) and the filesystem watcher, so `subscribe()` looked like it covered every write while silently missing all of them. The consumer that pays for this is ObjectQL's SchemaRegistry bridge — the component that decides what is queryable. #3108 worked around it for the `metadata:reloaded` seam by carrying the parsed artifact on the event payload, but the asymmetry remained for every other `register()` call site and every other `subscribe()` consumer. Announce by default, so a new call site is correct without knowing the contract exists. Two concrete fixes fall out: `unregisterPackage()` now tells cached consumers to drop uninstalled objects instead of serving them until restart, and runtime datasource writes reach watchers. Bulk ingest opts out explicitly via the new `MetadataWriteOptions` (`{ notify: false }`) at the five boot/batch sites, each of which either runs before consumers cache anything or announces the whole batch once. ObjectQL's registry bridge MUST stay silent for a second reason: it copies objects OUT of the SchemaRegistry, and announcing would feed them back through a handler that re-registers under `_packageId ?? 'metadata-service'` — overwriting the true package provenance of every object whose body carries no `_packageId`. Additive only: the 3-arg forms keep working, and the api-surface ratchet reports 0 breaking / 1 added. Tests pin both halves of the contract (announce by default, silence only when asked) and the no-flood invariant on the reload path; both were verified to fail against the pre-change behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(changeset): state the register() notify change as a contract fix, not a bug fix unregisterPackage()/bulkUnregister() have no production caller in framework or cloud today, so their announce is correct-but-latent. The one live behavior change is runtime datasource writes reaching the HMR SSE stream. Say so instead of advertising two 'concrete fixes'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题(15.1 第三方评估 P2 #3/#4/#5,合并修复)
三项 dev-loop DX 毛刺,全部在真实 create-objectstack 脚手架项目上复现,并用本分支 runtime 在同一项目上实测修复。
3. dev 热重载对新增对象不建表不跑 seed
watch 模式新增
*.object.ts后终端「✓ recompiled — server will auto-reload」全绿,但对象完全不可用直到手动重启。排查发现比评估报告还深一层:MetadataManager.register()根本不通知subscribe()订阅者——artifact 热重载后 ObjectQL 的注册表桥接从未触发,新对象连 SchemaRegistry 都进不去(REST 报not registered);建表只在 boot 跑;seed 只读 boot 时的 bundle(且 seed 无name,从不进 MetadataManager)。修复(各层各归其位):metadata:reloaded事件载荷携带解析后的 artifact 集合(seeds 只有这条通道)_packageId溯源)+ 重跑幂等 schema sync(尊重skipSchemaSync,串行化防 DDL 竞争)✚ new object(s): eval_app_tag — table & seeds sync on reload实测:server 运行中新增对象+seed → 3 秒内 REST 查询返回 3 行 seed 数据,零重启。kernel hook 按注册顺序串行(objectql 建表先于 runtime seed)。
4. dev 默认管理员账号不可见
终端凭据提示其实已存在,但只在「真正 seed 的那次 boot」显示——
os dev默认持久化 DB,第二次启动起就消失;登录页则完全无信号。修复:maybeSeedDevAdmin在「已有用户」分支追加探测:seed 账号仍存在且仍是默认密码(better-auth 原生password.verify对sys_account存储 hash 校验)→ 重新点亮devSeedResult,startup banner 每次 dev boot 都显示getPublicConfig()新增 dev-gateddevSeedAdmin字段(NODE_ENV==='development'双重门,生产由构造保证绝不出现),登录页横幅数据源(objectui PR 另发)实测三态:seed 首启显示 ✓ / 重启(不再 seed)仍显示 ✓ / 改密后重启消失 + config 字段消失 ✓。新增 3 个门控单测。
5. os doctor 引用分析误报
收集器读的几乎全是死字段(
view.object/nav.object/agent.objects在现行 spec 均不存在)。重写:defineView 容器全路径(list/listViews/form/formViews的data.object、subformchildObject、lookup 表单字段)、app 导航(objectName+ 嵌套children+areas,含requiresObject)、flow 节点config.object/objectName;删除死的agent.objects读取(消息同步改为 "view, flow, app, or lookup field");findOrphanViews同步下钻容器。实测对照(同一项目:task 仅容器视图绑定、tag 仅导航挂载、note 真孤儿):发布版 doctor 误报 3/3;本分支只报 note 1/3。
测试
cli 524 / plugin-auth 460 / objectql 905(含新增 reload-ingest 集成测试)/ runtime 544 / metadata 260(含 payload 契约测试)全绿;
pnpm build干净。🤖 Generated with Claude Code