Skip to content

spec(field): referenceDeletedWhen beside referenceVia, a declared predicate on a sibling select field that marks the referenced record as platform-deleted (objectui#12489 letter A) #23735

Closed

Description

@objectstack-fleet

Filing gate: the spec half of a maintainer ruling — objectui#12489, batch #352 item 4, letter A (the third face of ruling 6190549995 on objectui#12438). Filed by the director seat (summon #42, session_01AKVFxqmRLqktJspVXwPE9A). ⛔ Not a claim; the lane and grade are the ruling's.

What the ruling binds

FieldSchema gains an optional key beside referenceVia (packages/spec/src/data/field.zod.ts:1466 on origin/main 9bb93706fb): referenceDeletedWhen: { field, value }. field names a select field on the same object and value one of its declared options; any other shape is refused at parse, naming the field and the option. The spec seat spells the key by the spec's conventions (the dev's exact zod lines are in objectui comment 6198994393). Meaning: when the sibling holds that value, the referenced record was deleted by the platform's own assertion; a renderer draws the tombstone from the option's own label, reads nothing and links nothing.

Who produces it today

sys_approval_request.record_id with { field: 'cancel_reason', value: 'record_deleted' }: record_deleted is produced at plugin-approvals/src/approval-service.ts:4655 and declared in spec/src/contracts/approval-service.ts:118 (label 「Related record deleted」). That declaration is the services card filed beside this one, Blocked-by: this card. The objectui consumer (the record pointer renderer, Clause-②: yes) is objectui#12489's step 4, dispatched when the spec is installable at objectui's pin.

Clause-②: yes (widening: one optional key with one producer and one consumer). Contract review at CONTRACT_REVIEW_TIER by face. A liveness-ledger row for the key names both.

Dedupe: objectstack open titles read for referenceVia, referenceDeletedWhen, tombstone and deleted reference in this act: none.

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    First touch: lane confirmed; grade p3 → p1 + target:v18 by the protocol-first class · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T23:05Z

    Read in this act: the body in full, 0 comments, and the ruling 6203737086 on objectstack-ai/objectui#12489.

    ⛔ Not a claim.

  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 · 2026-10-15T23:10Z
    Session: session_01HjR8RUwTPQ3TgbfKihmxp9 (the dispatching seat; the dev runs as a cloud session the seat post names)
    Account: os-elon-musk (the seat's linked user as GET /user answers it; this card's assignee)
    Branch: claude/issue-23735-reference-deleted-when
    Worktree: objectstack-issue-23735 (in the cloud session's container)
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main 3b46855fb or later; stop on a breach and explain it in the report):

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23735,
      "status": "done",
      "branch": "claude/issue-23735-reference-deleted-when",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23759",
      "session": "session_01LSSHP4Yb97YuFXXzj85HMJ",
      "premise_still_valid": true,
      "summary": "FieldSchema gains referenceDeletedWhen: { field, value } directly after referenceVia, as a closed strictObject. Refusal 1 is in the FieldSchema superRefine beside the referenceVia checks: the key without referenceVia. Refusal 2 is refuseDishonestReferenceDeletedWhen in the ObjectSchema superRefine beside refuseNonPictureImageField. It is a PARSE-time check, not create()-only, so the builder, defineStack, raw parse and the save door all refuse. Each failure is one located custom issue at fields.FIELD.referenceDeletedWhen.field or .value, naming the field and the option: the field itself, an undeclared field, a non-select, a multiple:true select, a picklist-backed select with no inline options, or a value outside the declared options. Also: a planned liveness row drilled to field/value and naming #23736 (producer) and objectui#12489 step 4 (consumer), with no authorWarn per the settledWhen precedent; a composite form row; regenerated spec artifacts; and the changeset. Premise verified at 3b46855fb: sys_approval_request.cancel_reason is a single select with inline options holding record_deleted (plugin-approvals sys-approval-request.object.ts), so the producer shape #23736 will write passes. The card's claim was 'Clause-②: yes' and the newest Claim: names this branch. The card assignee was left untouched (os-elon-musk); the PR assignee mirrors it.",
      "tests": "All at head d13e56398 (after merging origin/main a869ea636) unless noted. @objectstack/spec test: 680 files, 20771 passed, 1 todo, exit 0. Spec typecheck exit 0 (includes check:test-typecheck). The new field-reference-deleted-when.test.ts: 15 passed. Consumers (dependents direction, filter '...@objectstack/spec' subset): @objectstack/objectql 427 files / 8148 passed, exit 0 at pre-merge head 24d0ca6d (the merge brought an objectql test file only). @objectstack/metadata-protocol 236 files / 20577 passed / 19 skipped, exit 0. @objectstack/lint 139 files / 6771 passed, exit 0. Before my pin bumps, metadata-protocol (1 failure: field 79 to 80) and lint (2 failures: 88 to 89 and 65 to 66) were red; they are census pins that grow with every new field key or form row. @objectstack/metadata-core 18 files / 728 passed, plus 53 passed in object-schema-fls-references.test.ts after the new pin, plus typecheck exit 0. @objectstack/platform-objects 70 files / 1091 passed, plus typecheck exit 0. @objectstack/driver-sql builtin-column-collision 11 passed, plus typecheck exit 0. ABLATION: node scripts/ablation-replace.mjs on packages/spec/src/data/object.zod.ts, anchor 'if (!declared.includes(value)) {' changed to 'if (false && ...)'. It landed (anchor 1 to 0, blob c7916c270c23 to 7872558d1f84), and the new suite went 3 failed / 12 passed (the value refusal, the save door and create()). It was restored with blob equal to HEAD c7916c270c23 and an empty git diff HEAD. No dist preflight was needed: the suite imports src through relative paths.",
      "gates": "Local, derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at d13e56398: 113 families. Each was run with its exit code captured before any pipe and recorded as 'CMD :: exit N'. Reconciled with --ran: '113 derived, 111 run, 2 NOT-MEASURED, 0 UNRUN', exit 0. 110 exited 0, including check:generated ('All 14 generated artifacts are up to date' after a real DTS spec build), check:liveness, check:i18n, check:docs, check:authorable-surface, check:api-surface, check:strictness-ledger, check:nul-bytes and check:changeset-gate-self-tests. check-plugin-teardown-shape --self-test first exited 3 on the shallow clone; after git fetch of its pinned fixture commit it exited 0. NOT MEASURED: check:skill-examples (exit 3, prerequisite refused); check:dual-build-cjs-loads (exit 3, nine packages have no dist); check:dts-closure (exit 1, 48 packages missing .d.ts). All three come from this container's own OS_SKIP_DTS turbo builds and are dist state, not a tree finding; CI builds fresh. After the final changeset-only commit 645116bef, these exited 0 on that content: check-changeset-no-major, check-adr-0087-registration, check-empty-changeset, check:published-files, check:nul-bytes. PR check-runs: in_progress at report time; not waited on, per contract.",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on #23735; read-only",
      "api_writes": "3 — git push (not a REST write); POST /repos/objectstack-ai/objectstack/dispatches carrying pr_create (relay POST /pulls draft and POST /issues/23759/assignees, run 38829797485, success, body read back 5271/5271 bytes identical); POST /repos/objectstack-ai/objectstack/dispatches carrying this os-dev-report comment on #23735. No label write: skip-changeset does not apply (the diff publishes four packages).",
      "line_budget": 593,
      "files_changed": [
        ".changeset/23735-reference-deleted-when.md",
        "content/docs/references/data/field.mdx",
        "content/docs/references/data/object.mdx",
        "content/docs/references/system/migration.mdx",
        "docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md",
        "packages/drivers/driver-sql/src/builtin-column-collision.ts",
        "packages/lint/src/validate-predicate-path-refs.test.ts",
        "packages/metadata-core/src/object-schema-fls-references.test.ts",
        "packages/metadata-core/src/object-schema-fls-references.ts",
        "packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/field-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/spec/authorable-surface/data.json",
        "packages/spec/liveness/field.json",
        "packages/spec/liveness/state-counts/field.md",
        "packages/spec/src/data/field-reference-deleted-when.test.ts",
        "packages/spec/src/data/field.form.ts",
        "packages/spec/src/data/field.zod.ts",
        "packages/spec/src/data/object.zod.ts"
      ],
      "deviations": [
        "File surface widened beyond the claim (field.zod.ts, tests, liveness row, spec artifacts, changeset). Reasons: (1) object.zod.ts holds the sibling half, as hypothesis 1 expected. (2) Exhaustive per-key tables pinned to the live FieldSchema shape: metadata-core FIELD_REFERENCE_POSITIONS (a new deletedWhen scrub plus a pin) and driver-sql FIELD_KEY_STORAGE_CLASS (presentation). (3) The form row's labels in the platform-objects catalogs, hand-translated zh-CN/ja-JP/es-ES, with two catalog census pins (669 to 672, 8 to 10). (4) Census pins in metadata-protocol (79 to 80) and lint (88 to 89, 65 to 66). Every item went red, or is pinned to go red, without its line. No plugin-approvals, platform-objects object or objectui file was touched.",
        "Changeset widened from spec-only to also list metadata-core, driver-sql and platform-objects as patch (commit 645116bef). That commit landed AFTER pr_create, so the PR body still says '@objectstack/spec minor' only and cites head d13e56398. The dev writes the body once; the seat may amend that line.",
        "PR body ends with the AGENTS.md session-URL footer only; the harness's separate PR attribution lines were dropped in its favour (AGENTS.md takes precedence).",
        "Primary checkout /home/user/objectstack was detached (git checkout --detach) so the worktree could take the dispatch branch, which the container had pre-checked-out there."
      ],
      "open_questions": [
        {
          "question": "Sibling-shape strictness beyond the ruling's letter ('a select sibling and one of its declared options'): this PR also refuses a multiple:true select and a picklist-backed select (no inline options). Keep both refusals?",
          "options": [
            "A: keep both. Axis 3: declared means enforced, and the parse cannot check a picklist option or give 'holds that value' a single reading on an array. The one named producer (cancel_reason) is a single select with inline options.",
            "B: accept picklist-backed selects and check the value against the picklist at a later seam (the stack or the save door)"
          ],
          "recommendation": "A. No producer needs B (axis 1). B moves the check to a seam the field parse cannot see, which axis 3 argues against. Axis 4: widening later costs nothing, narrowing later is breaking."
        },
        {
          "question": "Liveness row: planned without authorWarn (the field.settledWhen precedent), or authorWarn so an author is told nothing reads it yet?",
          "options": [
            "A: no authorWarn (as shipped). The authoring half is enforced, and the value takes effect with no re-authoring when the renderer lands.",
            "B: authorWarn. It would also warn on #23736's own platform declaration until objectui#12489 step 4 ships."
          ],
          "recommendation": "A, per README rule 1 and the settledWhen precedent."
        },
        {
          "question": "Location shape: hypothesis 1 asked for a 'located code + status-shaped issue where the parse surface has one'. The Zod parse surface carries code 'custom' plus a path, and no status. Pins assert code, path and the named subjects (field, option, declared set).",
          "options": [
            "A: accept the zod issue shape as shipped (the imageField precedent)",
            "B: add an envelope status at a door that has one"
          ],
          "recommendation": "A. The save door already maps these issues into its 422 envelope."
        }
      ],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — ObjectExtensionSchema-added fields are not judged by refuseDishonestReferenceDeletedWhen (the imageField precedent: the check reads the authored object's own field map). No producer extends an object with this key today. Only in PR Acceptance notes."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23759 comment 6205609062 · domain:spec seat 1 · session session_01HjR8RUwTPQ3TgbfKihmxp9 · 2026-10-16T01:01Z · the contract review (CONTRACT_REVIEW_TIER) and an all-green head stand before the queue.

    File surface amended for claim 6204194958, as the PR measured it. Each path is an exhaustive per-key table or census pin that a new FieldSchema key reaches:

    • packages/metadata-core/src/object-schema-fls-references.ts and its test;
    • packages/drivers/driver-sql/src/builtin-column-collision.ts;
    • packages/platform-objects/src/apps/translations/*.metadata-forms.generated.ts with two catalog pins;
    • packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts;
    • packages/lint/src/validate-predicate-path-refs.test.ts;
    • docs/audits/2026-07-unknown-key-strictness-ledger.counts/data.md.

    The changeset now also lists metadata-core, driver-sql and platform-objects (patch).

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #23759 → 8776119bdc · domain:spec seat 1 · os-elon-musk · session session_01HjR8RUwTPQ3TgbfKihmxp9 · 2026-10-16T01:46Z

    probe reading
    PR object merged 2026-10-16T01:46Z out of the merge queue; merge commit 8776119bdc
    origin/main git merge-base --is-ancestor 8776119bdc origin/main → exit 0
    merged vs reviewed head all 23 files' blobs at 8776119bdc equal the reviewed head 645116bef8's (ACCEPT 6205609062, contract review PASS 6205719731)
    queue branch no gh-readonly-queue/main/pr-23759-* ref remains
    mis-close scan the body's only closing keyword is Fixes #23735; this card closed completed

    State: pm:dispatched is removed in this act; domain:spec, priority:p1 and target:v18 stay. The cloud dev session is archived in this act. The out-of-scope note stands as written in the ACCEPT: a field that ObjectExtensionSchema adds is not judged, and no producer exists for one.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions