Skip to content

feat(spec,objectql): IObjectQLEngine —— objectql 槽的契约落地,类 implements 之,七个本地 stand-in 退场 (#4251 B3) - #4404

Merged
os-zhuang merged 3 commits into
mainfrom
claude/4251-b3-objectql-contract
Jul 31, 2026
Merged

feat(spec,objectql): IObjectQLEngine —— objectql 槽的契约落地,类 implements 之,七个本地 stand-in 退场 (#4251 B3)#4404
os-zhuang merged 3 commits into
mainfrom
claude/4251-b3-objectql-contract

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#4251B3,按 issue 上评估过的方案:objectql 一族不机械类型化,而是把契约写出来

IObjectQLEngine:objectql 槽的契约

ObjectQL 一个实例注册两个名字,ledger 现在能说清各自含义:

契约 视图
data IDataEngine(不变) 数据面
objectql IObjectQLEngine extends IDataEngine 完整引擎

新契约覆盖:schema 访问(getSchema / getObject / registry)、actions(registerAction / removeActionsByPackage / executeAction)、hook/middleware seams(registerHook / unregisterHooksByPackage / registerFunction / registerMiddleware / bindHooks)、first-wins 默认 runner 与 hook metrics、启动接线(registerDriver / setDatasourceMapping / registerApp)、运维探针(checkDriversHealth / wasDatastoreCreatedFromEmpty / invalidateDataMigrationFlags)。ledger 测试钉住新关系:objectql 严格加宽 data,刻意不再相等。

implements 是本 PR 的要点

两个批次以来的诚实状态记录在 DomainHandlerContext.getObjectQL 上:更宽的表面没有契约,把它标成 IDataEngine 会是"看着更舒服的谎"。过渡纪律 —— 每个消费方声明自己用的窄切片 —— 累积出七个本地 stand-in(AppEngineSurfaceEngineRegistrySurfaceEngineExtensionSurfaceSecurityEngineSurfaceFreshDatastoreEngine、dispatcher 的 inline checkDriversHealth 切片、getObjectQL: any 本身)。

每一个都诚实,每一个都是未经检查的 claim:getService<Surface>('objectql') 是断言,引擎改个名,七处消费方运行时全坏、编译期零报错。

ObjectQL implements IObjectQLEngine 把七份断言并成一份编译器验证的 claim。 七个 stand-in 全部删除;getObjectQL 端到端标成 Promise<IObjectQLEngine | null>,关闭 dispatcher 里最老的一处记录在案的 any

证据门槛不变:每个声明成员都有经槽到达的跨包调用方;没有的(如 triggerHooks,跨包只有测试在用)不入契约,等调用方出现。注册表视图 EngineSchemaRegistryView 恰好声明消费方在用的 8 个成员。

_registry 从此不出引擎包

plugin-security 的五处 declared-metadata 读取(readDeclared、permission-set projection、suggested audience bindings)一直在 any 下伸进 ObjectQL 的私有 _registry 字段 —— 与 B2 抓到的 /me/apps 同款,×5。全部迁到契约声明的公开 registry getter,测试替身同步。

顺带:IMetadataServicesubscribe? / loadMany?

MetadataManagerwatch 旁边一直实现着它们,唯一跨包调用方(ObjectQLPlugin 的 metadata bridge —— 保持 runtime-authored hooks/actions 活性的 re-sync)只能靠 any 够到。声明后,该 bridge 的 6 处 metadata 查找与 metadata-protocol 的 objectql 查找全部携带契约类型,两个文件整体退出祖父名单。

基线:167 → 159 站点,36 → 34 文件。

验证

  • pnpm check:slot-lookup 强制模式:✓ 159 unswept site(s) in 34 file(s), none new;no files added(对 d25a0ec)
  • spec build(dts)+ 7198 tests / 282 files;objectql build(即 implements 检查)+ 1464 / 89
  • runtime 1015 / 70、plugin-security 677 / 32、plugin-hono-server 135 / 12、plugin-auth 579 / 26、platform-objects 254 / 8、metadata 281 / 13、metadata-protocol 136 / 21
  • 八个被触包 dts build 全过;eslint 干净

🤖 Generated with Claude Code

…exists, the class implements it, the seven local stand-ins are deleted (#4251 B3)

The ledger can finally say what each of ObjectQL's two registration names
means: `data` stays IDataEngine (the data plane); `objectql` resolves to
IObjectQLEngine -- schema access (getSchema/getObject/registry), actions
(registerAction/removeActionsByPackage/executeAction), hook & middleware
seams (registerHook/unregisterHooksByPackage/registerFunction/
registerMiddleware/bindHooks), the first-wins default runners and hook
metrics, boot wiring (registerDriver/setDatasourceMapping/registerApp),
and ops probes (checkDriversHealth/wasDatastoreCreatedFromEmpty/
invalidateDataMigrationFlags). The ledger test pins the relation:
objectql strictly WIDENS data, deliberately no longer equal.

Why implements is the point: the honest state for two batches -- recorded
on DomainHandlerContext.getObjectQL -- was that the wider surface had no
contract, so seven consumer-local stand-ins accumulated
(AppEngineSurface, EngineRegistrySurface, EngineExtensionSurface,
SecurityEngineSurface, FreshDatastoreEngine, the dispatcher's inline
checkDriversHealth slice, getObjectQL: any). Each was honest and each was
an UNCHECKED claim: getService<Surface>() is an assertion, so an engine
rename would break every consumer at runtime with zero compile errors.
`ObjectQL implements IObjectQLEngine` turns all of them into one
compiler-verified claim; all seven are deleted, and getObjectQL is typed
Promise<IObjectQLEngine | null> end to end.

Evidence bar unchanged: every member has a cross-package consumer through
the slot; triggerHooks (cross-package only in tests) stays off.

_registry never leaves the engine package now: plugin-security's five
declared-metadata readers reached the private field through `any` -- the
same reach /me/apps had in B2 -- all migrated to the public getter the
contract declares, test doubles included.

IMetadataService gains subscribe?/loadMany? -- implemented by
MetadataManager beside watch all along, reached only via `any` by
ObjectQLPlugin's metadata bridge. With them declared, that bridge's six
lookups and metadata-protocol's objectql lookup carry contract types and
both files leave the grandfather list: baseline 167 -> 159 sites,
36 -> 34 files.

Verified: spec build + 7198/282; objectql build (the implements check) +
1464/89; runtime 1015/70; plugin-security 677/32; plugin-hono-server
135/12; plugin-auth 579/26; platform-objects 254/8; metadata 281/13;
metadata-protocol 136/21; all eight dts builds; ratchet holds 159/34
none new; eslint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 31, 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 31, 2026 12:07pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/l labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 9 package(s): @objectstack/core, @objectstack/metadata-protocol, @objectstack/objectql, @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec.

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

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/core)
  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/knowledge-rag.mdx (via @objectstack/core)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/core)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @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 @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @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 @objectstack/core, @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-protocol, @objectstack/objectql, @objectstack/runtime, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/core, packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @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 packages/objectql, @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/cli.mdx (via @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/core, @objectstack/objectql)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/plugin-auth, @objectstack/runtime)
  • 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/objectql, @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/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/plugin-hono-server, @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime, @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/core, @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/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/core)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/plugin-security, 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/core, @objectstack/metadata-protocol, @objectstack/objectql, @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/core, @objectstack/plugin-security, packages/runtime, @objectstack/spec)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @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/plugin-security, @objectstack/spec)
  • content/docs/permissions/sso.mdx (via @objectstack/plugin-auth)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/anatomy.mdx (via @objectstack/core)
  • content/docs/plugins/development.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/runtime, @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/core, @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/runtime)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/core, @objectstack/objectql, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/core, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/core, @objectstack/spec)
  • 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 packages/objectql, @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/objectql, @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/core, @objectstack/objectql, @objectstack/plugin-auth, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v15.mdx (via @objectstack/core)
  • content/docs/releases/v16.mdx (via @objectstack/plugin-hono-server, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/metadata-protocol, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security, @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/platform-objects, @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.

os-zhuang and others added 2 commits July 31, 2026 19:56
…plements check caught a second spec-internal double (#4251 B3)

Three fixes, all caught by gates:

1. security-plugin:880 -- the contract's getSchema returns `unknown`;
   narrow to EngineOwnedSchemaLike at the guard call (CI Build Core; my
   local batch had been aborted by an earlier failure and I re-ran only
   the failed package -- the DEBT-package lesson, second verse).

2. objectql plugin.ts:1583 -- optional-member narrowing does not survive
   into a closure (TS2722); take a bound reference under the guard.

3. IMetadataService.subscribe -- the first draft reused `watch`'s
   callback type, and `MetadataManager implements IMetadataService`
   REJECTED it: subscribe relays the persistence-side MetadataWatchEvent
   (add/changed/deleted + path/stats), not watch's registration-level
   events. The check working exactly as intended, on its first day.
   Fixing it exposed that spec carries TWO types named MetadataWatchEvent
   with different shapes (system/metadata-persistence.zod vs
   kernel/metadata-loader.zod) -- the same double-source shape as the
   http-server shadow, both alive this time. Reported on #4251; merging
   them is its own change. The contract now imports the persistence one
   the implementation uses, with the trap documented at the import.

Verified: all nine touched packages' dts builds in ONE uninterrupted
batch; spec 7198/282, objectql 1464/89, metadata 281/13,
plugin-security 677/32; eslint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ract exports (#4251 B3)

`check:api-surface` is spec's public-API snapshot gate, and it reported
exactly what this PR does: "0 breaking (removed/narrowed), 2 added". The
two are IObjectQLEngine and EngineSchemaRegistryView; the regenerated
snapshot diff is +2 lines, -0 -- purely additive, matching the gate's own
count.

Missed because I ran spec's build and tests but not its check:* gates.
#4361 ran all of them; this PR did not. All 16 now pass locally
(check:exported-any included -- the contract's deliberate `any`s at the
framework-handle and engine-local-shape edges are within its allowance).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@os-zhuang
os-zhuang merged commit 7ce02eb into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/4251-b3-objectql-contract branch July 31, 2026 12:21
os-zhuang added a commit that referenced this pull request Aug 1, 2026
…11 names declared twice with different shapes (#4411) (#4458)

* refactor(spec)!: remove the kernel metadata-loader envelope family — 11 names declared twice with different shapes (#4411)

`@objectstack/spec` exported eleven names TWICE, with a different shape each
time, on two subpath entries — so which type a consumer got depended on nothing
but the import path:

    import type { MetadataWatchEvent } from '@objectstack/spec/kernel';   // one shape
    import type { MetadataWatchEvent } from '@objectstack/spec/system';   // another

`MetadataFormat`, `MetadataStats`, `MetadataLoadOptions`, `MetadataSaveOptions`,
`MetadataExportOptions`, `MetadataImportOptions`, `MetadataLoadResult`,
`MetadataSaveResult`, `MetadataWatchEvent`, `MetadataCollectionInfo` and
`MetadataLoaderContract` are removed from `kernel/metadata-loader.zod`. The
`system/metadata-persistence.zod` copies stay as the single source.

Why the kernel side goes, and why this was worth removing rather than living
with:

- Zero consumers. Import-statement scans across this repo, `cloud` and
  `objectui` find every consumer on `./system` (or `./contracts`' own
  interface); only `kernel/metadata-loader.test.ts` ever parsed the kernel
  copies. ADR-0049 enforce-or-remove.
- The naming intuition pointed the wrong way, which is what made this sharper
  than an ordinary duplicate. The kernel copies were the ones that LOOKED
  canonical — normalized enums, required fields, a `.describe()` per property —
  and they were the dead ones; the live copy is the loose superset its own
  consumer calls "legacy". Picking by name, or by which reads as more rigorous,
  picked the dead one, and because the shapes overlap heavily that choice
  compiled and failed later, at an edge value (`add` vs `added`) or on a field
  one copy made required.

No tombstone and no ADR-0087 conversion, deliberately: these are runtime
envelope types, not authorable metadata, so no authored source can carry them
and there is nothing for `os migrate meta` to rewrite (the plugin-runtime /
dev-plugin precedents).

`MetadataManagerConfig` and `MetadataFallbackStrategy` are untouched — they were
never duplicated (kernel owns them, system re-exports them), and that is the
split that survives: manager wiring is kernel's, the loader/watch envelope is
system's, nothing is declared twice. `MetadataManagerConfig.formats` now reads
the `shared` format enum (same four members, leaf module, no cycle) rather than
a fourth local copy.

Also:
- `contracts/metadata-service.ts` drops the "spec carries TWO types named
  MetadataWatchEvent" warning added in #4404 — it no longer does.
- `expression-conformance.ledger.ts` drops the now-absent
  `kernel/metadata-loader.zod.ts:filter` CEL surface (the surviving system
  options never declared a `filter`, so no loader predicate was ever evaluated
  through it).
- Baselines dropped deliberately: `json-schema.manifest.json` −11 entries,
  `authorable-surface.json` −65 lines (nothing can author these, so no
  `[RETIRED]` markers). `api-surface.json` regenerated: 22 exports leave
  `./kernel`. `references/kernel/metadata-persistence.mdx` removed by
  `gen:docs`. v17 release notes + upgrade checklist extended.

No runtime behaviour changes — nothing read the removed copies. The system
shapes are NOT tightened here; narrowing them would be a separate change.

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

* chore(spec): write the hand-edited baselines the way the generator does

The two baselines this branch edits by hand — `json-schema.manifest.json` and
`authorable-surface.json` — came out with `—` escaped as `—`, because the
edit went through Python's `json.dump`, whose `ensure_ascii` defaults to true.
`build-schemas.ts` writes them with `JSON.stringify`, which emits the character
literally.

No gate catches this: the manifest is only rewritten when the SCHEMA KEY SET
changes, so the escape would have sat in the file until the next PR that adds a
schema, where the generator would silently rewrite it back and hand that author
an unrelated one-line diff to explain.

Re-serialised with `ensure_ascii=False`. Both files now differ from main by
exactly the intended removals and nothing else: 11 manifest keys, 65
authorable-surface lines, zero incidental churn.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant