Repository navigation
docs(spec, skills): a queried composite record title is a stored computed field, not a formula; a stored field's expression is the engine's, never a client hint - #25183
Conversation
…uted field, not a formula Re-words the `titleFormat` describe, the reconciliation note that quotes it, the objectstack-data skill's `nameField` / `titleFormat` rows and its "Computed column" bullet to the ruling's shape: a composite title that import, sort or search must match is a stored computed field (a non-formula field with an `expression`, computed and stored on every write); a text formula stays legal for display only; a stored field's `expression` is computed by the engine, never a client hint. Claude-Session: https://claude.ai/code/session_01T1Y1g92DfSEz93iuCisju4 Co-authored-by: Claude <noreply@anthropic.com>
`pnpm --filter @objectstack/spec check:generated --fix` after the build; only `check:docs` was stale, and the diff is the four `titleFormat` rows on the object, metadata and migration reference pages. Claude-Session: https://claude.ai/code/session_01T1Y1g92DfSEz93iuCisju4 Co-authored-by: Claude <noreply@anthropic.com>
…ting stale text The re-worded `nameField` row put the file 48 tokens over its ceiling. Paid in the same file: the two re-worded rows are tightened, the incident sentence "It used to clear both and then never match" is dropped, the parenthetical pointing at "the determinism gate above" (which lives in references/seeds.md, not above) is dropped, and a doubled `---` separator is removed. The file now reads 6099 of 6123 tokens. Claude-Session: https://claude.ai/code/session_01T1Y1g92DfSEz93iuCisju4 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 144 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 6bfb7adf8213fe55d7617abdf033502e8ae72916 && git checkout 6bfb7adf8213fe55d7617abdf033502e8ae72916
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b6e870707b95d7b8ee9cedd68ad358b51de0da91 e747839220be43ed47f475df379e33bc482f340f && git checkout -B drift-repro b6e870707b95d7b8ee9cedd68ad358b51de0da91 && git merge --no-ff e747839220be43ed47f475df379e33bc482f340f
node scripts/docs-audit/affected-docs.mjs --json b6e870707b95d7b8ee9cedd68ad358b51de0da91
|
Contract reviewServed-tier: The rest of the diff — the changeset file and the three regenerated reference pages under ① Derived judgmentsEvery accept-set and public-surface change the diff implies, each named right or wrong:
② Semver level
Clause-②: no ③ Boundary flagsDev report 6334913572 — seven
Governance: Check-runs on Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读
席位核对ACCEPT ·
Generated by Claude Code |
Fixes #25129
Clause-②: no
Metadata-protocol: none
Governance: Tier H. This diff touches
skills/**(the publishedobjectstack-dataskill), a governed surface, so it lands only on an authorized APPROVED review. It stays a draft until then; the relay'spr_createrequests the governed review itself.What changes
Ruling 6308445871 (#24981, letter A), item 2: "The producer stores the title it needs to query: a composite title that must round-trip through import is a stored computed field (a non-formula field with an
expression, written on write — the #24619 shape), the remedy ADR-0079 item 9 already prescribes for sort and search." PR #25127 (#25071) re-worded the record-title lint, ADR-0079 D3 andformulas.mdxto that shape. This PR finishes the same reconciliation on the copies that card did not claim, and keeps "a text formula title stays legal for display only".packages/spec/src/data/object.zod.ts, thetitleFormatdescribecontent/docs/references/data/object.mdx,references/api/metadata.mdx,references/system/migration.mdx(two rows)pnpm --filter @objectstack/spec check:generated --fixafter the build; the diff is the fourtitleFormatrows and nothing elsepackages/spec/src/system/metadata-form-zod-reconciliation.test.ts, thetitleFormatomit-ledger noteskills/objectstack-data/SKILL.md,nameFieldrowreturnType: 'text') for a composite title"formulafield with anexpression, computed and stored on write); a text formula is display-only"skills/objectstack-data/SKILL.md,titleFormatrowreturnType: 'text'formula field asnameField"nameFieldrow"skills/objectstack-data/rules/relationships.md, the "Computed column" bullet (seat pointer 6333459023)type: 'formula'as computed, so on a stored field theexpressionis a client compute hint and the sent value is stored verbatim"expressionfrom the row the write stores and stores the result, so a client-sent value never stands"The
nameFielddescribe carries no composite-to-formula prescription (measured; the dispatch's H2 is falsified for that site). Its TSDoc lists "formula→text" among the stored title fields, D1's wording that ADR-0079's addendum qualifies without editing; it prescribes nothing for a composite title and is left alone.The shape is real on origin/main
FieldSchema.expressiondescribe (packages/spec/src/data/field.zod.ts): "On any other (stored) field: computed by the engine from the row the write stores and stored, so a client-sent value never stands".packages/objectql/src/engine.tsplanStoredExpressions/replacedStoredExpressionFields;packages/spec/src/contracts/data-engine.ts: since objectql 18.x: understrictReadonlyWrites, refuse a write whose value a stored expression replaces (stored_expression), the deferred half of #24690 #25000 astrictReadonlyWriteswrite whose value such a field's expression replaces is refused, and a non-strict one is reported understored_expression.Sweep (H2, H3)
packages/spec/src/**: "composite" with "formula", "nameField" or "title" → the describe and the reconciliation note only (control wordtitleFormat: 10 files, none a prescription).skills/**: "composite" with "formula", "title" or "nameField" → the two SKILL.md rows only; "compute hint", "stored verbatim", "only treats", "as computed" → the relationships.md bullet only (control wordtitleFormat: 3 hits; the other two are the formula skill's template table and a query-filter example, neither a prescription).rules/field-types.md:124already says aformulais virtual, consistent with the new text.packages/*/CHANGELOG.md(release-owned; never edited in a code PR) and in two test docblocks describing landed in-repo migrations (packages/services/service-messaging/src/objects/notification-display-title.test.ts:18,packages/platform-objects/src/identity/identity-display-title.test.ts:17), the in-repodisplay_titleformulas the card excludes.skills/** readings
Published:
@objectstack/skills(packages/skills,publishConfig.access: public, in the changesetfixedgroup) shipsskills/**asdist/skills/SKILL_NAME/…throughscripts/sync-catalog.mjs, withfiles: ["dist", "README.md", "CHANGELOG.md"]. So the skill half owes a changeset; it rides in the same file as the spec half.Lines (budget: at most +2 net across
skills/objectstack-data/):skills/objectstack-data/SKILL.mdskills/objectstack-data/rules/relationships.md.mdunderskills/objectstack-data/skills/**/SKILL.mdsummedTokens (
scripts/check-skills-token-ratchet.mjs,ceil(utf8 bytes / 4), release stamp unpriced):skills/objectstack-data/SKILL.mdskills/objectstack-data/rules/relationships.mdThe first re-wording of the
nameFieldrow putSKILL.md48 tokens over its ceiling (6171 / 6123). Paid in the same file by deletion, never by re-wrap: the two re-worded rows tightened; the incident sentence "It used to clear both and then never match." dropped; the parenthetical "(Reminder: two consecutiveos buildruns with no source change must be byte-identical — see the determinism gate above.)" dropped, because that gate lives inreferences/seeds.md, not above; a doubled---separator removed. No ceiling moved.Tests
Measured at head
e74783922(baseab488d9b7;origin/mainhas since gained three commits that touch none of these paths, so no pre-PR merge):pnpm --filter @objectstack/spec build, under the shared verify lock:VERDICT command-exit 0.packages/spechas no workspace dependencies, so the ① closure build is empty.pnpm --filter @objectstack/spec check:generated:check:docswas the one stale artifact of 14;--fixregenerated it (under the lock,VERDICT command-exit 0); the re-check reads✓ check:docs.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2over the six spec test files that mentiontitleFormat(the reconciliation note among them):Test Files 6 passed (6),Tests 267 passed (267),VERDICT command-exit 0. Declared narrowing: the spec suite is 779 files, over the foreground cap; only the reconciliation note pins the changed text and no test reads thetitleFormatdescribe; CI'sTest Coreruns the whole suite.pnpm --filter @objectstack/spec typecheck(tsc,check:scripts-typecheck,check:test-typecheck):VERDICT command-exit 0.Gates
Derived on the final commit with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths; "gate list derived from the tree of 'objectstack-ai/objectstack' at commit e747839"): 119 commands. Each was run from the worktree root with its exit code captured before any pipe and recorded asCOMMAND :: exit N;--ranthen read: "119 derived famil(ies) accounted for — 118 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)".check:docs,check:generated,check:skill-docs,check:skill-refs,check:skill-examples(after building@objectstack/client-react/@objectstack/client, its declared prerequisite),check:skills-token-ratchet,check:skill-identifier-liveness,check:skill-frame-sync,check:skill-compatibility,check:doc-authoring,check:doc-formula-expressions(after building@objectstack/formula/@objectstack/lint, its declared prerequisite),check-empty-changeset,check-changeset-no-major,check-adr-0087-registration,check:nul-bytes,check:pm-governed-merges.pnpm check:dual-build-cjs-loads, exit 3 (PREREQUISITE NOT MET: it reads every package'sdist/, a whole-repo build); CI runs it. The diff changes no build output shape.node scripts/check-skills-token-ratchet.mjsbefore and after the payment (✗ over by 48, then✓ 54 authored bundle file(s) within their ceilings).Changeset
.changeset/25129-composite-title-stored-field.md:@objectstack/specpatchand@objectstack/skillspatch,Clause-②: no,Metadata-protocol: none. The text an author reads changes; no key, type, default or accepted value does.Acceptance notes
nameFieldTSDoc's "(text / autonumber / formula→text)" lists a formula among the "real stored" title fields, D1's wording that the ADR-0079 addendum qualifies without editing; it prescribes nothing and is not in scope. Noted, not filed.维护者速读(草稿)
titleFormat的 describe(及其三页生成的参考文档)、引用它的表单对账注记,以及已发布的objectstack-data技能包里nameField/titleFormat两行和「Computed column」一条。措辞统一为:需要被导入匹配、排序或搜索的组合标题应使用存储型计算字段(非 formula 字段加expression,写入时由引擎计算并落库);text formula 标题仍合法,但只用于展示。「Computed column」改为:存储字段的expression由引擎按写入行计算并落库,客户端送来的值不作数。skills/**,属 Tier H,需要一次授权的 APPROVED 评审后才能落地。Generated by Claude Code