Repository navigation
docs(spec): register the user-field deleteBehavior enforcement as an ADR-0087 semantic entry and correct the delete-walk prose (#29415) - #29553
Conversation
…emantic entry and correct the delete-walk prose (#29415) Item A: semantic migration entry user-field-delete-behavior-enforced; the #29253 changeset's ADR-0087 marker becomes registered and its stored-row paragraph names the entry. Item B: FieldSchema docblocks and the user reference refusal message, the user-field-foreign-reference-refused entry, the hook-context referential markers and the getCascadeDeleteObjects docblock say a user field joins the walk when it declares deleteBehavior. Both metadata forms show deleteBehavior on a user field. The api/protocol.zod.ts cascadeDeleteObjects describe is held for the protocol.ts freeze. Claude-Session: https://claude.ai/code/session_01JQwxbZAexDYPqzEmBW5tH9 Co-authored-by: Claude <noreply@anthropic.com>
…ar describe (#29415) Claude-Session: https://claude.ai/code/session_01JQwxbZAexDYPqzEmBW5tH9 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 18 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 6 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 168 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 2417bd15c045c7f17578243be5abb9b60e29dbe5 && git checkout 2417bd15c045c7f17578243be5abb9b60e29dbe5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 32907ae9ce0f020a966c5363eaca2a688240e47a 59709cbbbd3c3120beafbca1a265710d227ab7ba && git checkout -B drift-repro 32907ae9ce0f020a966c5363eaca2a688240e47a && git merge --no-ff 59709cbbbd3c3120beafbca1a265710d227ab7ba
node scripts/docs-audit/affected-docs.mjs --json 32907ae9ce0f020a966c5363eaca2a688240e47a
|
…eBehavior gates respelled as in-lists (#29415) Claude-Session: https://claude.ai/code/session_01JQwxbZAexDYPqzEmBW5tH9 Co-authored-by: Claude <noreply@anthropic.com>
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract-review-claim: session_01AavokzJ5DndAwitDXvKy4U · head 59709cb · 2026-11-02T20:58Z Taken under (b): the head has waited 119 min, with no record, claim or hold. Generated by Claude Code |
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Contract reviewServed-tier: Inputs read: card #29415, PR #29553's body, its 12 files, and the net diff against ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentThe entry records the one thing an upgrading author must do, which is read each Tried to break it:
Must-fix: none. Should-fix:
Landing condition: Check Changeset stays red by design, and this record is its confirmation. The Test UI red is #29468's. Both are named here, so the PR may enter the queue with them under SKILL.md's three conditions. VERDICT: PASS Generated by Claude Code |
|
domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1 Contract-review-hold: session_01JQwxbWR3K3h7i1ytwycVg1 · head 59709cb · card #29415 item B still owes the Warren relayed that freeze at 2026-11-02T17:19Z. The lane runs ONE at-tier review on the post-freeze head. That review also judges the DELIBERATE CORRECTION of |
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz Superseded by #29712: the same three commits ( |
Requested by Warren · project thread
Fixes #29415
Clause-②: no
Metadata-protocol: none
维护者速读
user-field-delete-behavior-enforced;修正 spec 里仍说「user 字段从不参与删除联动」的文字;字段设计器与对象表单在 user 字段上也显示 deleteBehavior 控件。objectstack migrate meta和升级指南都看不到这次行为变化;Studio 也无法在 user 字段上编写这个键。deleteBehavioron auserfield parses but the delete walk never reads it, sorestrict/cascadeon a user field are not enforced #29253 的 changeset(未发布)同步改为registered,因此check-empty-changeset按设计保持红灯,需要你在本 PR 上确认这次更正。回滚即 revert。deleteBehavioron auserfield parses but the delete walk never reads it, sorestrict/cascadeon a user field are not enforced #29253 未发布 changeset 的这次更正(check-empty-changeset 的人工确认路径)。What changes
A. ADR-0087 semantic entry (
packages/spec/src/migrations/entries/semantic/18.user-field-delete-behavior-enforced.ts, iduser-field-delete-behavior-enforced). PR #29368 made a declareddeleteBehavioron auserfield take effect when the user is deleted. No key moved, so there is no conversion; the entry records the judgment the consumer owes, following the two 18.x precedentsfield-master-detail-set-null-refusedanduser-field-foreign-reference-refused:object.fields[].deleteBehavior(andobjectExtension.fields[].deleteBehavior) on atype: 'user'field;set_nullon every type can carry aset_nullnobody authored. On a non-required field that is accepted as it is (it clears the field, as on alookup); on arequiredfield it now refuses the user delete with 409DELETE_RESTRICTEDwherever clearing would leave the field empty;requiredfield carriesset_nullonly where the refusal is intended, and a test delete gives the declared outcome per field.The entry reaches the generated registry (one hit for the id in the gitignored
registry.ts), andcheck:spec-changes/check:upgrade-guideproject it in memory.The #29253 changeset (
.changeset/29253-user-field-delete-behavior.md, unreleased; added to the claim by amendment 6584095382). Finding A of contract review 6579523704: its ADR-0087 marker goes fromnot-required (no-migration-prescription)toregistered user-field-delete-behavior-enforced, and its "Rows stored before #9784" paragraph now names the entry and the fix. The marker's old "there is no stored value for a conversion to rewrite" clause, which contradicted that paragraph, is gone with it.B. Spec prose that said a
userfield never joins the delete walk:data/field.zod.ts: thedeleteBehaviordocblock (FieldSchema.deleteBehaviordefaultsset_nullonto EVERY field type, so built artifacts ship the key ontext/datetime/numberfields #9784 paragraph), the.overwritecomment, the comment above theuserreference refusal, and the refusal message itself ("auserfield never did" becomes "auserfield has no default and keeps the id unless it declares one");user-field-foreign-reference-refused: "which auserfield never did" becomes "which auserfield that declares nodeleteBehaviordoes not do";data/hook.zod.ts: thereferentialFieldCleardocblock and describe, and thereferentialCascadeDeletedocblock, now nameuserbesidelookup/tree;content/docs/references/data/hook.mdxis regenerated for the describe (gen:docs);contracts/objectql-engine.ts: thegetCascadeDeleteObjectsdocblock namesuser.⛔ Held, owed after the freeze:
packages/spec/src/api/protocol.zod.ts, the twocascadeDeleteObjectsdescribes (GetMetaItemResponseSchemaandGetMetaItemCachedResponseSchema's sibling text, which enumeratemaster_detail/lookup/tree). protocol.ts is frozen until 2026-11-03 06:00Z at the latest; the seat sends that edit after the freeze lifts.Forms.
data/field.form.tsanddata/object.form.tsshoweddeleteBehavioronly forlookupandmaster_detail. Thelookupbranch now readsdata.type in ['lookup','user']in both files, so a Studio author can set the key on auserfield with all three outcomes. Auserfield has no default, and the metadata-admin select prefills nothing, so the control writes a value only when the author picks one.Why
Contract review 6579523704 on PR #29368, should-fixes A and B; triage 6583845201 grades it p1 because both ship with 18.3.0.
Tests
packages/spec/src/data/form-delete-behavior-options.test.tsgains two cases per form: auserauthor sees exactly one control offering all three values, and atextauthor sees none.44bec0e9: with bothvisibleWhenrules put back todata.type == 'lookup'(zero hits of the new spelling on disk after the swap), the suite reported2 failed | 16 passed (18), the twousercases, one per form; restored fromHEAD,git diff HEADempty.pnpm --filter @objectstack/spec testunder the verify lock: Test Files 792 passed (792), Tests 23526 passed and 1 todo; lock VERDICT command-exit 0.Verification
pnpm --filter @objectstack/spec build(VERDICT command-exit 0), thencheck:generated: one stale artifact (content/docs/references/**, from the hook describe), regenerated withgen:docs, then all 14 up to date.check:spec-changesandcheck:upgrade-guide: exit 0.node scripts/pm/dispatch-gates.mjs --commands, 106 commands): run from a runner that recordsCMD :: exit N, measured on head21cd9672, and reconciled with--ran: 106 derived, 105 run, 1 NOT-MEASURED, 0 UNRUN (dispatch-gates --ranexit 0). Of the 105, 104 exit 0 and one exits 1:check-empty-changeset --base origin/main, by design (see Acceptance notes). Two first runs exited 3 (prerequisite) and were re-run after the prerequisite:check-plugin-teardown-shape --self-testafter fetching its pinned fixture commit (then exit 0, 48 cases), andcheck:i18nafter building its extract closure (then exit 0, 10 packages in sync). NOT MEASURED:check:dual-build-cjs-loads(exit 3, it needs every package built); CI runs it.Acceptance notes
check-empty-changesetstays red by design: this PR rewrites a pending release note it did not add (the objectql:deleteBehavioron auserfield parses but the delete walk never reads it, sorestrict/cascadeon a user field are not enforced #29253 changeset). That is the gate's DELIBERATE CORRECTION class; its remedy is a confirmation on the PR, not a restore. The rewrite is the one the contract review asked for and the seat's claim amendment 6584095382 adds to this card's surface.deleteBehaviorcontrol in both forms is still hidden fortree, whose parse materializesset_nulland which the walk reads. Nothing in this card asks for it.userfield'sdeleteBehaviorbut cannot clear a stored one; clearing stays a Source-tab edit.userfield's declareddeleteBehaviornow takes effect when the user is deleted (#29253) — the field-type and relationship rules should say so #29400 (open).Human Minimum
packages/specholds no runtime logic.pnpm lintpasses. (No formatter ran.pnpm lintwas not run locally: it is CI's run.)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code