Skip to content

spec(migrations): register the user-field deleteBehavior enforcement (#29253) as an ADR-0087 semantic entry and stop the spec prose saying a user field never joins the delete walk #29415

Closed

Description

@objectstack-fleet

domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

Source: the contract review of PR #29368 (#29253), should-fixes A and B. The server PR lands as is. Both items need packages/spec/**, which the server card could not touch.

A. ADR-0087 entry. #29368 makes a declared deleteBehavior on a user field take effect when the user is deleted (restrict → 409, cascade deletes holders, set_null clears). No key moved, but an accepted declaration's enforcement changed, and a stored population exists: objects saved before #9784 may carry a materialized set_null on a user field. The two 18.x semantic entries field-master-detail-set-null-refused and user-field-foreign-reference-refused are the precedent. Add a SemanticMigration entry under packages/spec/src/migrations/entries/semantic/ so that objectstack migrate meta and the upgrade guide reach it. Its consumer judgment: set_null on a non-required user field is accepted as is. A required user field carrying the era set_null now refuses the delete with 409; the author removes the declaration or picks the behaviour they want.

B. Spec prose that says a user field never joins the walk (read on main; recheck after #29368 merges):

  • field.zod.ts: the .overwrite comment and the user-reference refusal message.
  • The D3 entry text.
  • hook.zod.ts: the referentialFieldClear / referentialCascadeDelete describes.
  • contracts/objectql-engine.ts: the getCascadeDeleteObjects docblock.
  • api/protocol.zod.ts: the cascadeDeleteObjects describe.
  • field.form.ts / object.form.ts: these show deleteBehavior only for lookup / master_detail, so Studio cannot author or clear it on a user field. Add user to the visibility rule.

Text, the entry, and the form visibility rule only. No runtime change. Lands after #29368.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p1 (was p2) · domain:spec kept · 2026-11-02T17:32Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

    Claim: PM loop round 2
    Session: session_01JQwxbWR3K3h7i1ytwycVg1
    Account: os-warren
    Branch: claude/project-thread-t4r2s3 (card thread; the thread can push only its own branch — measured platform exception to claude/issue-29415-…)
    Worktree: objectstack-issue-29415
    Domain: domain:spec
    Seat: domain:spec#5
    File surface: item A — a new entry under packages/spec/src/migrations/entries/semantic/ plus its registry and generated guide rows; item B — prose in packages/spec/src/data/field.zod.ts, the D3 entry text, packages/spec/src/data/hook.zod.ts, packages/spec/src/contracts/objectql-engine.ts; the deleteBehavior visibility rule in packages/spec/src/data/field.form.ts / object.form.ts; .changeset/29415-user-delete-behavior-entry.md. ⛔ packages/spec/src/api/protocol.zod.ts is held: protocol.ts is frozen until 2026-11-03 06:00Z at the latest (the maintainer, in this account's project, 2026-11-02T17:19Z: 「server 席 5 宣布冻结 protocol.ts,最晚到明早 06:00Z」); its cascadeDeleteObjects describe is sent to the dev after the freeze.
    Container & model: M, mode:thread, model: TIER_DEFAULT, effort: xhigh (p1) requested; the thread runs at the project default, only the maintainer sets effort
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card (documents PR #29368's merged semantic change)
    Thread-read: 6583845201
    Premise: holds — PR #29368 merged (fe5ed7c310); triage 6583845201 grades p1 because both items ship with 18.3.0.
    Serial constraints cleared: PRs #29513, #29423, #29370, #29190 each add their own semantic entry file under migrations/entries/semantic/ (distinct files; any shared registry or generated guide row is ordinary concurrency, later lander merges main and regenerates); no open PR touches the item B files (census of 52 open PRs at 2026-11-02T17:43Z).

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

    Claim amendment to 6584072606 (same session, same branch claude/project-thread-t4r2s3).
    File surface: adds .changeset/29253-user-field-delete-behavior.md (unreleased): its adr-0087 marker becomes registered with the new entry's id, and its "no stored value for a conversion to rewrite" clause is reconciled with its own "Rows stored before #9784" paragraph — finding A of contract review 6579523704 on PR #29368, owed once this card's entry lands.

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#5 · os-warren · session_01JQwxbZAexDYPqzEmBW5tH9
    os-dev-report

    {
      "issue": 29415,
      "status": "done",
      "branch": "claude/project-thread-t4r2s3",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29553",
      "session": "session_01JQwxbZAexDYPqzEmBW5tH9",
      "premise_still_valid": true,
      "summary": "Item A: new semantic entry user-field-delete-behavior-enforced (packages/spec/src/migrations/entries/semantic/18.user-field-delete-behavior-enforced.ts) with the review's consumer judgment (non-required set_null accepted as is; required set_null now refuses the user delete wherever clearing would leave the field empty); per claim amendment 6584095382 the #29253 changeset marker is now registered user-field-delete-behavior-enforced and its stored-row paragraph names the entry, replacing the contradicting no-stored-value clause. Item B: field.zod.ts (deleteBehavior docblock, .overwrite comment, refusal comment and message), the user-field-foreign-reference-refused entry, hook.zod.ts referentialFieldClear docblock+describe and referentialCascadeDelete docblock, objectql-engine.ts getCascadeDeleteObjects docblock; hook.mdx regenerated. Both forms show deleteBehavior on user (data.type in lookup,user). OWED AFTER THE FREEZE: packages/spec/src/api/protocol.zod.ts, the two cascadeDeleteObjects describes (GetMetaItemResponseSchema and GetMetaItemCachedResponseSchema), not touched. PM assumptions measured: no runtime change (no file outside packages/spec, .changeset, content/docs/references); Clause-2 no; Metadata-protocol none; spec patch changeset .changeset/29415-user-delete-behavior-entry.md. No gate read the protocol kind otherwise.",
      "tests": "head 21cd9672: pnpm --filter @objectstack/spec test under the lock: Test Files 792 passed (792), Tests 23526 passed and 1 todo, VERDICT command-exit 0. form-delete-behavior-options.test.ts 18/18 (2 new user cases + 2 text controls). Reverse verification on 44bec0e9: visibleWhen put back to data.type == lookup in both forms (0 hits of the new spelling on disk), suite 2 failed / 16 passed, the two user cases; restored from HEAD, git diff HEAD empty. No dist-resolved subject, so no ablation build leg.",
      "gates": "spec build VERDICT 0; check:generated: content/docs/references stale from the hook describe, gen:docs, then all 14 up to date; check:spec-changes 0; check:upgrade-guide 0. dispatch-gates --commands at 21cd9672: 106 derived; --ran: 105 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. 104 exit 0. check-empty-changeset --base origin/main exit 1 BY DESIGN: deliberate correction of the pending #29253 release note; needs confirmation on the PR, never a restore. Re-runs after prerequisites: check-plugin-teardown-shape --self-test 3 then 0 (fetched pinned 621a4876); check:i18n 3 then 0 (extract closure built, 10 packages in sync). NOT MEASURED: check:dual-build-cjs-loads exit 3 (needs every package built), left to CI. PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no bang in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay pr_create (PR 29553, 8816 bytes sent and stored identical) and this os-dev-report comment via post-stamped; git push is not a REST write",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: the deleteBehavior control in field.form.ts and object.form.ts is still hidden for tree, whose parse materializes set_null and which the delete walk reads",
        "carrier: none · noted, not filed: the metadata-admin select has no empty option, so the form can set a user field's deleteBehavior but cannot clear a stored one (Source-tab edit only)",
        "carrier: #29400 · skills-docs follow-up for the enforcement, already open"
      ],
      "body_amendments": "none now; after the freeze the protocol.zod.ts edit lands and the body's Held paragraph becomes done"
    }
  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

    Claim amendment · 2026-11-02T18:53Z

    File surface adds packages/lint/src/validate-predicate-path-refs.test.ts. The #7010 corpus census pin moves 65 → 63, because PR #29553 respells both deleteBehavior gates as data.type in ['lookup','user'], an in-list outside the ==/!= census. Test Core (6/8) is red on head 21cd9672 for this reason. The patch round has been sent to the card thread. The rest of the claim stands, and protocol.zod.ts stays held until the freeze lifts.

  6. added a commit that references this issue on Nov 2, 2026
  7. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1

    Release: claim on this card (session session_01JQwxbWR3K3h7i1ytwycVg1), on the seat's stand-down. Order: Warren, 「spec 当前任务处理完,走下班流程」, project chat (relayed by the coordinator).
    Resume-from: claude/project-thread-t4r2s3@59709cbbbd3c3120beafbca1a265710d227ab7ba
    Restart-when: the protocol.ts freeze lifts (announced by server seat 5; 2026-11-03 06:00Z at the latest).

    State for the next seat:

    The order was written at 2026-11-02T23:52Z.

  8. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Claim: PM loop round 1
    Session: session_01WGufzhJG3tKnksHVa1krBz
    Account: os-support-ai
    Branch: claude/project-thread-fbdrz1 (card thread, executor session_01WGufzgmDWPyn8w47uKA3CW; the thread can push only its own branch, the measured platform exception to claude/issue-29415-…)
    Worktree: objectstack-issue-29415
    Domain: domain:spec
    Seat: domain:spec#2
    File surface: the delta owed by Release 6591556737 — packages/spec/src/api/protocol.zod.ts (the two cascadeDeleteObjects describes and their [#28001] docblocks only) and packages/spec/src/data/field.zod.ts ≈L1822; their regenerated artifacts (content/docs/references/**, schema / api-surface outputs); .changeset/29415-user-delete-behavior-entry.md. Inherited from the resumed commits: the PR #29553 file list (12 files).
    Container & model: S, mode:thread, model: TIER_DEFAULT (reason: no CONTRACT_REVIEW_TIER work in-seat, the account's at-tier budget is spent, maintainer 2026-10-28; the review owed goes to triage), effort: xhigh (p1)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6591556737
    Premise: holds — PR #29368 merged; the freeze that held protocol.zod.ts was lifted at 6588593530 (server seat 5, #28677); protocol.zod.ts on origin/main 744211fc still carries the unedited cascadeDeleteObjects describes (≈:767, ≈:2501) and field.zod.ts ≈L1822 on the resume head still reads "AUTHORS one".
    Resume-from: claude/project-thread-t4r2s3@59709cbbbd3c3120beafbca1a265710d227ab7ba
    Serial constraints cleared: #29441 (this seat, claude/project-thread-0neu2n) edits GetMetaItemsRequestSchema in the same file (≈:242) and PR #29628 edits the device-registration schemas (≈:3519+): different regions, ordinary concurrency, the later lander merges main and regenerates. No open PR touches field.zod.ts ≈L1822.

  9. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzgmDWPyn8w47uKA3CW
    os-dev-report

    {
      "issue": 29415,
      "status": "done",
      "branch": "claude/project-thread-fbdrz1",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29712",
      "head": "72a8bffd9fa53f37ade9a33e0e3e80ab0e825a27",
      "session": "session_01WGufzgmDWPyn8w47uKA3CW",
      "premise_still_valid": true,
      "summary": "Resumed from claude/project-thread-t4r2s3@59709cbb (PR #29553's three commits unchanged) and merged origin/main twice (83189767 onto 744211fc, clean; 72a8bffd onto 1c1a5d40). The second merge conflicted in field.form.ts: #29639's referenceNameVisible row sits directly above the deleteBehavior row. Resolved by keeping both. Delta: (1) protocol.zod.ts GetMetaItemResponseSchema.cascadeDeleteObjects describe now reads 'a lookup, tree or user field that declares deleteBehavior: cascade', the objectql-engine.ts wording; the engine already admits it (getCascadeDeleteObjects -> cascadeRelationBehavior -> statesDeleteSemantics). Of the four sites the order named, only this one listed relation kinds; the cached describe and both [#28001] docblocks list none and imply nothing about user, so they are untouched. (2) field.zod.ts deleteBehavior docblock: 'AUTHORS one' -> 'declares a deleteBehavior', parenthetical re-wrapped. (3) gen:docs regenerated protocol.mdx (1 row) and app-bundle.mdx (5 rows). (4) The 29415 changeset, still a spec patch, names the protocol description and gains a 'Supersedes, in the same release' bullet: the unreleased #28001 note lists the cascading relations with the same lookup-or-tree sentence. The #28001 file is not edited. Text only: no accept set moved (Clause-2 no, Metadata-protocol none).",
      "files_changed": {
        "delta_commits": [
          "8f1dfc7a2c",
          "8ce9dc0588",
          "8954056920"
        ],
        "delta_files": [
          ".changeset/29415-user-delete-behavior-entry.md",
          "packages/spec/src/api/protocol.zod.ts",
          "packages/spec/src/data/field.zod.ts",
          "content/docs/references/api/app-bundle.mdx",
          "content/docs/references/api/protocol.mdx"
        ],
        "merge_resolution": [
          "packages/spec/src/data/field.form.ts (72a8bffd)"
        ],
        "pr_vs_main": "15 files, +150 / -42 (the 12 inherited from #29553 plus app-bundle.mdx, protocol.mdx, protocol.zod.ts)"
      },
      "line_budget": "size S: the delta commits change +16 / -14 over 5 files; the whole PR vs main is 192 changed lines, under the 3000 human-merge threshold",
      "tests": "head 72a8bffd, one locked run, VERDICT command-exit 0: pnpm --filter @objectstack/spec test -> Test Files 803 passed (803), Tests 23790 passed | 1 todo; pnpm --filter @objectstack/spec typecheck -> tsc --noEmit, check:scripts-typecheck, check:test-typecheck OK (52 files / 240 errors / 131 pinned signatures held); pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-predicate-path-refs.test.ts -> 62 passed (62), with predicates 91 (main) and comparisons 63 (branch). Pre-second-merge head 89540569: spec 802/802 files, 23736 passed | 1 todo, typecheck exit 0. No test added: describe and comment text only, and nothing parses it. No ablation: no tested behaviour changed.",
      "gates": "head 72a8bffd. Full build first: turbo run build --filter=!@objectstack/docs --concurrency=2 under the lock, 117/117 tasks, VERDICT command-exit 0. Then spec check:generated: all 14 up to date. dispatch-gates --commands derived 105 commands, run serially with CMD :: exit N recorded: 104 exit 0, and 1 exits 1 by design (check-empty-changeset --base origin/main on .changeset/29253-user-field-delete-behavior.md, the DELIBERATE CORRECTION #29553 already carried). dispatch-gates --ran: 105 derived, 105 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. check:dual-build-cjs-loads, NOT MEASURED on #29553, is exit 0 here (115 entry points, 70 packages). Local-only: check:dev-prereqs 0, check:skill-frame-freshness 0. PR check-runs: in_progress at report time (PR just opened).",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — reads went through unauthenticated api.github.com curl and git fetch",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls -> #29712, 9927 bytes, read back identical, assignees none) and this comment through scripts/pm/post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/29415/comments); plus git push x5 to claude/project-thread-fbdrz1 (not REST)",
      "deviations": [
        "PR attribution link: line 2 points at this card thread (cmsg_01BVUyyPie8gHwoPM18iABwBTc1Gxk14k2PbeArtFLuL8a), which the harness's required attribution block names verbatim, not at the seat-2 thread the order quoted",
        "protocol.zod.ts: 1 of the 4 named sites edited; the other 3 measured to carry no relation-kind list and no user-field claim",
        "changeset: added a 'Supersedes, in the same release' bullet for the unreleased #28001 note (same sentence as the old describe); .changeset/28001-cascade-delete-objects-beside-item.md itself untouched",
        "second origin/main merge (72a8bffd) with one hand-resolved conflict in the inherited file packages/spec/src/data/field.form.ts; both intents kept, rerun of os-regen-merge.sh, rebuild and full re-verification on the new head",
        "pr_create sent no assignees and no reviewers (os-dev.md rule 2, fleet-write ops.mjs header), although the harness default asks to assign the requester",
        "PR body declaration lines come before the 维护者速读 block (os-dev.md order), with Fixes #29415 and the Supersedes #29553 line directly under the attribution block"
      ],
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  10. added a commit that references this issue on Nov 3, 2026
  11. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Landed. PR #29712 merged through the queue (merge commit 63f962f8); this card closed as completed by its Fixes line.

    Reading Value
    PR #29712 MERGED at 2026-11-03T03:54Z, head abde58e1, contract review PASS 6594347454 + delta 6594438289
    Card #29415 closed (completed)

    State change: pm:dispatched removed. The two unreleased changeset corrections (#29253, #28001) shipped as authorized by the maintainer. Left elsewhere: #29733 (the Studio select's missing empty option on a user field, ui/). #29553 stays closed as superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions