Uh oh!
There was an error while loading. Please reload this page.
fix(objectql): MetadataFacade reads return the stored document — content is a real authorable field, not a storage envelope - #8377
Conversation
…ent is a real authorable field, not a storage envelope (#7519) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDTnVvsgA6cUZ4xFVtPZRy
…7519) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDTnVvsgA6cUZ4xFVtPZRy
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also reference the affected code. These are read-only:
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7519
What
MetadataFacade.get,list, andlistNamesunwrapped every stored item through thecontent-or-item fallback (and acontent-dot-namefallback limb inlistNames), presumingcontentmarked the facade's own storage envelope. Butcontentis a real authorable field —packages/spec/src/system/doc.zod.tsdeclares it as the doc's required raw-Markdown body (line 92 at HEAD, located by symbol), andpackages/spec/src/ai/knowledge-document.zod.tsdeclares it on both of its shapes — soregister('doc', name, document)followed byget('doc', name)answered the Markdown string instead of the document: truthy, string-typed, silent. That is exactly the silent non-round-trip the #7378 three-cell ruling (2026-08-12) forbids:register(t, n, d)thenget(t, n)round-trips or refuses loudly.All three reads now return the stored document verbatim.
Why removal, not a renamed envelope
The envelope the unwrap presumed has no producer — measured, not assumed:
nameargument as IMetadataService's effective key (#7378) #7511 cell 3). fix(core,metadata,objectql): enforce the #7378 three-cell IMetadataService register ruling in every shipped implementation #8349 replaced it with the shared guard's loud refusal (assertMetadataRegisterContract), so the facade never writes an envelope.loadMetaFromDb, metadata-protocol) parses thesys_metadata.metadatacolumn and registers the parsed document itself — never a wrapper.SchemaRegistry.registerItemcaller stores the document as-is, keyed byname.With no envelope on any write path, an unwrap on the read path can only corrupt. And because no replacement envelope key is introduced, there is no next authorable key to collide with — the collision surface is gone, not moved. This is a restore-the-invariant change riding the #7378 ruling, not a second envelope beside it.
Both directions pinned
metadata-facade.test.ts: adocwith realcontentround-trips whole throughget/list/listNames/exists/getEntry; aknowledge_documenttoo; and a content-less document still round-trips unchanged (the surviving path).metadata-service-roundtrip-conformance.test.ts(the "beyond the table" block — deliberately NOT the shared table, which lives underpackages/spec/src/and is the spec seat's half ofMetadataFacadeanswers threeregister→getround-trip cases differently from every other shippedIMetadataService#7378, tracked on spec: the IMetadataService contract still states the SUPERSEDED 2026-08-11 register ruling — including a "do not implement" instruction for behaviour now shipped (#7378 spec half) #8350; that scope is untouched here): all four shippedIMetadataServiceimplementations agree acontent-carrying document round-trips whole.listNamesfallback limb was dead in both directions (the envelope nothing produces, and a real doc whosecontentis a string has nocontent.name) — removed, with the measurement in the docblock.Reverse verification — direction predicted before running
Predicted: with the unwrap restored from
origin/main, theget-document,list,knowledge_document, and conformance (MetadataFacade subject only) pins go red;listNames/exists/getEntry/ content-less pins stay green, because those members already answered name-carrying documents correctly. Observed exactly that: 4 failed, 98 passed. Fix restored from the committed branch, not from working-tree memory.Blast radius
Re-measured at HEAD:
new MetadataFacadeappears only in test files and one migration doc — no production caller constructs one. The defect stays dormant until a host wires the facade; the class is exported from the package root, so downstream hosts pick up the fix via the changeset (patch,@objectstack/objectql).Verification
@objectstack/objectqlsuite: 196 files, 3506 tests, all green.pnpm --filter @objectstack/objectql typecheckclean.check:durability-log-level,check:engine-double-contract,check-engine-split-ratio(informational),check:query-options-erasure(test-surface ceiling unchanged),check:type-check-coverage,check:nul-bytes— all green;dispatch-gates.mjsre-derived on the changed paths names no family beyond these.Generated by Claude Code