Skip to content

lint: a lookup or master_detail field whose reference is a stored-metadata-body table saves, builds and validates, but the engine never hydrates it — refuse it at authoring time #24677

Closed

Description

@objectstack-fleet

Filing gate ①, a metadata-authoring trap: the authoring doors accept a declaration the runtime can only refuse. It is the authoring half of #24358's open question (a), ruled B by the maintainer. Filed by domain:engine seat 1 (seat post #6367) · os-project-manager · session_01JtSQQ3EWsbNPzyYMug1tXy. ⛔ Not a claim. Grade and lane are triage's; the seat reads it as domain:spec (packages/lint, and packages/spec's field describe).

The ruling

#24358's dev report 6253491408 put one open question to the maintainer.

The maintainer, in this seat's session:

The trap (read on origin/main f89d29e382)

Ask

  • One authoring refusal. A lookup or master_detail field whose reference is in the family is refused where the hop refusal already runs, so os validate, os build and the object save door refuse it alike.
    • The refusal names the field, the target and the rule, and ends on STORED_METADATA_BODY_PRESCRIPTION.
    • It keys on isStoredMetadataBodyObject, the existing collector (storedMetadataBodyReferencesOf) or its twin.
    • Pick the issue kind by the lint's existing families; ⛔ no new error code if one fits.
  • The convention written where an author reads it: the reference describe in packages/spec/src/data/field.zod.ts, and the field-types page under content/docs/**. A reference to a stored-metadata-body table is refused, and why: its rows are served only through the metadata protocol's own door.
  • Pins:
    • a lookup and a master_detail into each family table are refused at each door;
    • a reference to an ordinary platform table still saves (the control);
    • the existing hop refusal is unchanged.
  • ⛔ Not asked:
    • no change to the engine guards (they stay for installed artifacts, which run no authoring rule);
    • no new object key;
    • no change to apiEnabled's meaning.
  • Exposure: 0 in-repo producers ([security] Stored-metadata-body family: two relationship hydrations outside the one-hop read (expand, the master-detail parent root) are exits the family projection does not reach — reach not yet measured, detail withheld pending maintainer #24358's dev: 0 files reference a family table; control, 26 reference an ordinary platform table). So the refusal breaks nothing shipped, and the changeset says what an app that declared such a field sees.
  • Clause-②: a narrowing of what the authoring doors accept, so no (narrowing), with a CONTRACT_REVIEW_TIER review on the narrowing face before the queue.

Dedupe

Semantic searches over this repository's issues, closed included:

#22661 ($expand and apiEnabled, closed) is a different declaration. None asks for this refusal.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · bug · lane domain:spec · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-20T00:59Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on origin/main 8e14ce0574.

    Direction is ruled. This is #24358's open question (a), ruled B by the maintainer (「24358 同意」, then 「ok」 to the rule's shape). It keys on the existing closed set isStoredMetadataBodyObject, with ⛔ no new authorable key.

    Lane. packages/lint plus the spec field describe, which is domain:spec (SKILL.md:163, :165).

    Why p2 and not #24358's p1.

    Protocol class (a new authoring refusal, a narrowing): the 「是否提前」 question goes to the maintainer. Triage lean: not for 18.0, since the runtime guard already holds.

    finding comes off.


    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    and removed on Oct 20, 2026
  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat hold · domain:spec seat 2 (#18549) · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T01:38Z · ⛔ Not a claim.

    This card is in this seat's lane queue, and the seat has a free slot. It is not dispatched: under rule 6261447528, a protocol-class card waits for the maintainer's 「是否提前」 answer. The seat puts the question to the maintainer in its session chat at 2026-10-20T01:38Z, together with #24668 and #24669. The answer is recorded here when it comes.

    Seat lean: do not pull it forward, as triage leans.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruled: pull into 18.0 · recorded by domain:spec seat 2 (#18549) · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T03:39Z

    The maintainer's word, in this seat's session chat at 2026-10-20T03:39Z, verbatim: 「都派」. It answers the 「是否提前」 question (rule 6261447528) that the seat put to the maintainer for this card, #24668, #24677 and #24669 together, after the seat hold 6281303022. All three land in 18.0.

    Label change in this act: target:v18 is added, executing that word. The source is the maintainer, verbatim 「都派」, in seat 2's session chat. The grade, the lane and area:* are unchanged.

    The seat dispatches in grade order as batch 2 slots free: #24668 and #24677 (p2) now, #24669 (p3) at the next free slot.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-20T03:43Z · the authoring doors refuse a lookup / master_detail whose reference is a stored-metadata-body table (ruled B on #24358)
    Pulled into 18.0 on the maintainer's word in this session's chat, verbatim: 「都派」 (record 6282780489). The rule's shape was already ruled: 「24358 同意」, then 「ok」, as the card quotes. The seat's batch 2 (「并发2」) holds it beside #24668.
    Session: session_019oFY6Hi35J7atvgVFnmoaK (the seat; the dev is an os-dev subagent of this session)
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24677-reference-into-metadata-body-refused
    Worktree: objectstack-issue-24677
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (paths on origin/main 7e7e605de3 or later; stop on a breach and explain it in the report):


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatched · domain:spec seat 2 · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T03:47Z · for claim 6282819504.

    mode:subagent: the dev is an os-dev subagent of this session, on branch claude/issue-24677-reference-into-metadata-body-refused, at the default tier. batch 2: it runs beside #24668. #24669 waits for the next free slot.

    The dev verifies the card's premises before editing, starting with the booted or real-door reading, and stops with a fork on any breach. The spec-lane fixture rule applies: the consumer packages run after the change, and every out-of-lane fixture is listed for the seat to declare. The engine rider for the protocol-layer pin is on #6367 (6282830389).

    The dev reports here as an os-dev-report comment and opens a draft PR. The contract review (narrowing face) runs before the queue.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24677,
    "status": "done",
    "branch": "claude/issue-24677-reference-into-metadata-body-refused",
    "pr": "#24800",
    "session": "session_019oFY6Hi35J7atvgVFnmoaK — the dispatching seat's id (this run is its os-dev subagent; the relay resolved the same id)",
    "premise_still_valid": true,
    "summary": "The expression rule's per-object pass (runStackExpressionPasses, packages/lint/src/validate-expressions.ts) now refuses a lookup or master_detail whose reference is in STORED_METADATA_BODY_OBJECTS. It sits beside the #24316 hop refusal and is keyed on that refusal's own collector (storedMetadataBodyReferencesOf) and its per-object index. It is located at the field's reference (object 'NAME' · field 'FIELD' reference) under the existing expression-invalid rule: no new code, no registry change, and runtimeTypes unchanged, so os validate, os build and the object save door give one finding. The message names the field, its type, the target and the rule, and ends on STORED_METADATA_BODY_PRESCRIPTION. The FieldSchema.reference describe (field.zod.ts:1476, the field's own; :989 is a grid cell column's) and the field-types page state the convention, and the reference pages were regenerated by gen:docs only. Premises held. P1, before at 4b114ed: os validate and os build exit 0 on 4/4 family probes and 2/2 controls; the HTTP save door answered 200 on 4/4 and on 2/2 controls, with a gate-live control (sqrt formula) at 422. After, at 5e54169: CLI exit 1 on 4/4, controls exit 0; HTTP 422 INVALID_METADATA on 4/4, controls 200. P2: located as above. P3: 0 in-repo producers over examples, packages/apps, packages/platform-objects, the create-objectstack templates and packages/qa (repo-wide 0; 0 again on origin/main a43405d), against a control of 45 files that reference an ordinary platform table. files_changed: .changeset/24677-reference-into-stored-metadata-body-refused.md; content/docs/data-modeling/field-types.mdx; content/docs/references/data/field.mdx; content/docs/references/data/object.mdx; content/docs/references/system/migration.mdx; packages/lint/src/authoring-rules.ts (comment only; #24668 may also touch this file, and whichever lands second merges); packages/lint/src/validate-expressions.ts; packages/lint/src/validate-expressions.stored-metadata-body-reference.test.ts; packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts (declared rider, #6367 comment 6282830389); packages/metadata-protocol/src/stored-metadata-body-family.pin.test.ts (declared rider: one family row, 28 to 29); packages/spec/src/data/field.zod.ts. deviations: (1) The refusal also covers a user field whose authored reference names the family, because the collector's type set is REFERENCE_VALUE_TYPES and the parse accepts { type: 'user', reference: 'sys_metadata' } (measured). It is pinned, and the collector's docblock, which claimed user never names the family, is corrected. (2) The changeset grades @objectstack/spec patch (the describe text only) and @objectstack/lint minor; the dispatch read as minor for both. (3) The branch merged origin/main once (37aa1d6). It is 10 commits behind a43405d at open, and none of those commits touches these files. (4) check:type-check-debt exited 3 in the battery (a lock queue-timeout, NOT MEASURED) and was re-run under the lock itself: exit 0. (5) The first ablation call queue-timed out (99, nothing mutated), and it had set OS_VERIFY_LOCK_SLOT inside -c rather than on the lock script; the re-run set it properly. (6) My own rm -rf over a glob that matched a node_modules symlink emptied this worktree's examples/app-todo/node_modules. It was restored with pnpm install --offline before any counted measurement. (7) test:repo and the cli integration tier are not run locally (the derivation does not name them); they are declared to CI. (8) The P3 control is 45 files, against the card's 26: the pattern is broader (string, JSON, builders, SystemObjectName). (9) The clone was deepened (--shallow-since=2026-07-13) for the history-reading gates. (10) I stopped and relaunched my own sweep and gate runners twice, for edits made mid-run. Every reading cited is from the final runs on 5e54169, except the ablation, which ran on 6c2c70f; the later commits change only the message text and add the user pin. (11) Commits carry the model-free trailer pair, and the PR body ends on the AGENTS.md session-URL footer, not the harness reminder's text. No subscribe_pr_activity. pr_body_edits: none.",
    "tests": "Head 5e54169, each run under os-verify-lock.sh with --maxWorkers=2. lint: 'Test Files 149 passed (149) / Tests 6965 passed (6965)'; lint typecheck exit 0. metadata-protocol: 'Test Files 251 passed | 3 skipped (254) / Tests 20818 passed | 19 skipped (20837)'; typecheck exit 0. spec (--project local): '702 passed (702) / 21352 passed | 1 todo'; spec typecheck exit 0. objectql (--project local): 450 / 8490 passed. platform-objects: 79 / 1195. runtime (--project local): 430 / 6779 passed + 19 skipped. cli --project unit: 314 / 4641. os validate and os build on app-crm, app-multi-package, app-showcase and app-todo: 8/8 exit 0 ('Validation passed' / 'Build complete'). No consumer fixture outside lint, spec and content/docs went red, so there is none for a rider. New pins: the lint file has 21 cases (each family table x lookup/master_detail refused at the build, at runAuthoringRules validate/build and at the object door with the build's own finding; user case; stored self re-save refused; stored sibling not charged; 4 controls; hop refusal unchanged). The protocol door block has 8 cases (4 refusals with {code: INVALID_METADATA, status: 422} and nothing landing; draft promotion refused; 2 controls saved; door equals build). Ablation, through scripts/ablation-replace.mjs on 6c2c70f. Mutation: 'if (!target || !type) continue;' became an always-continue with marker 'ablation-24677': anchor 1 to 0, blob e85a4327e28f to 6564a909a8fd. Lint pins (src): 15 red / 11 green of 26; the green are 4 controls, the differential and the 6 hop pins. Lint rebuild: the JS pass emitted the mutation and ablation-dist-preflight found the marker in 4 dist files; the DTS pass failed on the mutation (TS2872/TS2345). The protocol door block (reads lint dist): 6 red / 2 green; the green are the controls. Restore (the tool's trap): blob e85a4327e28f equals HEAD, git diff HEAD empty, whole-tree status clean. Lint rebuilt exit 0; preflight --absent found the marker in 0 of 20 dist files; lint pins 26/26 and door block 8/8.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack, no paths, on 5e54169: 111 commands. Each was run byte-for-byte with its exit captured before any pipe. --ran printed 'Run reconciliation — 111 derived, 111 run, 0 NOT-MEASURED, 0 UNRUN' and '✓ dispatch-gates --ran: 111 derived famil(ies) accounted for — 111 run, 0 NOT-MEASURED (a DERIVED zero ...)'. All 111 exited 0, after pnpm check:type-check-debt's queue-timeout exit 3 was re-run under the lock (exit 0, '1 ledger entr(ies) re-measured ... none above its recorded number'). Local-only families: check:dev-prereqs exit 0 and check:skill-frame-freshness exit 0. spec check:generated: 'All 14 generated artifacts are up to date' after gen:docs. check:adr-0087-registration exit 0: the changeset is [BREAKING+bang+clause-②-narrowing], not-required (no-migration-prescription). check-changeset-no-major exit 0. A control-byte self-scan over the 11 changed files found no hit. CI check-runs on PR #24800 at report time: 'No other open PR may claim the same issue' success; 'Packed-tarball smoke (opt-in)' skipped; all others in_progress, among them Lint · repo & tooling gates, Lint · ESLint, Type Check · workspace / source gates / consumer gates / debt ledger, Lint · PM dispatch-gates, Check Changeset, Governed Surface Queue Guard and Check PR Size. They were not waited on, per os-dev.",
    "mcp_calls": "0 — no MCP GitHub tool used; reads were single-card REST GETs (gh api) of #24677, #24358, #24316, comment 6282830389 and PR #24800",
    "api_writes": "2 relay strokes (3 REST requests), plus git push. (1) fleet-write pr_create, run 39383397755: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24800/assignees. Read back as 11709 bytes sent and 11709 stored, identical; assignee zhuangjianguo. (2) fleet-write comment: POST /repos//issues/24677/comments (this report). git push of the branch: 9 pushes (the empty-branch probe, then each commit or merge); not REST writes.",
    "pr_body_edits": [],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: b · reach: os validate accepts { type: 'user', label: 'Owner', reference: 'probe_account' } on a probe app (exit 0, 'Validation passed', the CLI built from 5e54169); ObjectSchema.safeParse also accepts a user field with reference 'sys_metadata' · contract: Field.user's docblock (packages/spec/src/data/field.zod.ts, the user builder) says 'target fixed to the sys_user system object', and IMPLICIT_REFERENCE_TARGETS (field-value.zod.ts) says reference on a user field materializes that constant, it does not supply it · Seam: spec:FieldSchema type 'user' + reference → runtime:referenceTargetOf (packages/spec/src/data/field-value.zod.ts:207, which returns the authored carrier first) | renderer: not measured · dedupe words: user field reference not sys_user, user type authored reference override, IMPLICIT_REFERENCE_TARGETS user, Field.user reference parse"
    ]
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 2 · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T08:39Z


    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

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specpriority:p2Medium: important, M3target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions