Skip to content

[finding] showcase field-zoo's f_master_detail is the only master_detail in any authored corpus without required:true — one line, seed rows already comply #13723

Closed

Description

@os-warren

Handed over by the #13699 census run (read-only dispatch, fenced from filing) and filed by the dispatching seat (session_01PBjwYLS6BciTQW3c9xQiD2).

Measured: examples/app-showcase/src/data/objects/field-zoo.object.ts:107 — f_master_detail lacks required: true, the single such object across all 95 objects in the 6 loadable authored corpora (census on #13699). Both seed rows already set the value, so adding the line changes no data and turns nothing red; it is also the one tree-wide red a future global escalation of relationship/master-detail-required would hit, so fixing it now zeroes that migration list. One-line example hygiene; graded by triage as usual.

Refs: #13699 (census, closed duplicate of #9139) · #9139 (ruled v18 carrier).

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 31, 2026
  2. os-warren commented on Aug 31, 2026

    @os-warren
    CollaboratorAuthor

    分诊定级 → domain:spec · p3 · documentation · pm:queue。摘 finding。

    锚定。 落点是 examples/app-showcase/src/data/objects/field-zoo.object.ts。按车道表,examples/* 归它演练的子系统,而这里演练的是 relationship/master-detail-required 这条契约 ⇒ domain:spec。

    在 origin/main 上复核,卡片属实:

    examples/app-showcase/src/data/objects/field-zoo.object.ts
        f_master_detail: Field.masterDetail('showcase_project', { label: 'Master-Detail → Project' }),
                                                                  ↑ 没有 required: true

    ⇒ 一行,加 required: true。

    定级 p3。 卡片自己论证得很干净,我照它判:两条 seed 行已经都设了值,所以加这行不改任何数据、不弄红任何东西;它是纯粹的示例卫生。

    ⭐ 但它有一个不该被忽略的次要价值:这是全部 6 个可加载创作语料、95 个对象里唯一一个缺 required: true 的 master_detail。⇒ 它也是未来若把 relationship/master-detail-required 全局升级为强制时,全树唯一会变红的那一处。现在修掉等于把那次迁移的清单清零。

    ⇒ 派单时把这句写进去:这不是「顺手改个示例」,是提前把一次未来迁移的成本降到零。 一行换一张空的迁移清单,是这轮里性价比最高的几件之一。

    ⚠️ 它与 #9139 的关系要说清楚,别混:#9139 是被裁定的 v18 承载卡(全局强制),本卡不是它的一部分,也不阻塞它。本卡只是让那条路径落地时无事可做。⛔ 不要把本卡改成「实现全局强制」。

    Refs:#13699(普查,已作为 #9139 的重复关闭)· #9139(被裁定的 v18 承载卡)。


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 2, 2026
  4. claude commented on Sep 2, 2026

    @claude
    Contributor

    Claim: PM loop, domain:spec seat (seat post #6017)
    Session: session_01GDA48PuRFrHyRfdkBz8m21
    Branch: claude/issue-13723-field-zoo-master-detail-required
    Worktree: objectstack-issue-13723
    Domain: domain:spec
    File surface: examples/app-showcase/src/data/objects/field-zoo.object.ts (one line: required: true on f_master_detail, line 107 on origin/main 6aea1f55) + whatever showcase test/snapshot pins that object's shape. No packages/spec/src/** edit.
    Container & model: S, mode:subagent, default os-dev tier (no contract change).
    Clause-②: no (example hygiene; the census claim is re-measured in the PR body).
    Serial constraints: no in-flight writer of the showcase field-zoo object in this lane.


    Generated by Claude Code

  5. claude commented on Sep 2, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13723,
      "status": "done",
      "branch": "claude/issue-13723-field-zoo-master-detail-required",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14449",
      "head": "e9c424e79",
      "premise_still_valid": true,
      "summary": "Premise re-checked on origin/main at merge base 6aea1f559 and it held: examples/app-showcase/src/data/objects/field-zoo.object.ts:107 declared Field.masterDetail('showcase_project', { label: ... }) with no required: true. Added required: true, spelled the way the sibling single-line declarations in team.object.ts spell it. One line, one file. Census re-measured rather than trusted: 7 Field.masterDetail() declarations across the loadable authored corpora (app-showcase, app-crm, app-todo, packages/apps, create-objectstack templates, platform-objects), exactly 1 missing required:true — this one. A second sweep for the bare type:'master_detail' field-literal spelling returns nothing in those corpora, so the builder scan is the complete population. Both seed rows already supply the value (seed/index.ts:338 'Website Relaunch', :351 'Data Platform'; they are the only two records in that seed), so no data changes. Correction I am flagging rather than hiding: the branch commit message names objectstack validate as the warning command. That is wrong and the PR body says so. The rule lives in packages/lint/src/data-model-rules.ts and reaches the CLI via objectstack lint; measured, objectstack validate prints 33 warnings byte-identically on both trees and never reads this rule. I did not amend, because the commit was already pushed and force-push is banned; the squash body comes from the PR body (verified against how #14090 landed on main), so the inaccurate text never reaches main. Contract-doc conflict to flag: os-dev.md routes skip-changeset by the criterion 'publishes nothing from any package', but its closed list enumerates only docs/adr, .claude, scripts/pm, tests/workflow and comment-only diffs — examples/** is not on it. I followed the criterion plus the dispatch instruction plus repo precedent (#14090, an examples-only diff that landed carrying skip-changeset and no changeset), and examples/app-showcase is \"private\": true. Flagging the closed list gap rather than silently picking a side. Observed and NOT filed, because it is pre-existing and unmoved by this PR: objectstack validate emits 33 advisory warnings on the showcase on both the pre-fix and post-fix trees, one of which names showcase_field_zoo as a detail object with no object-level CRUD grant in any permission set. Identical before and after, so this PR neither causes nor clears it; raising it here so the PM can judge rather than letting it disappear.",
      "tests": "All heavy commands via scripts/pm/os-verify-lock.sh (slot issue-13723); verdicts read from the printed VERDICT line, exit codes captured before any pipe (cmd > log 2>&1; EXIT=$?). pnpm --filter '@objectstack/example-showcase^...' build — VERDICT command-exit 0 (dependency closure; run before anything was judged). pnpm --filter @objectstack/example-showcase typecheck — VERDICT command-exit 0; script name echoed (\"> @objectstack/example-showcase@0.3.16 typecheck\" then \"tsc --noEmit\"), so not a zero-match false green. pnpm --filter @objectstack/example-showcase exec vitest run --maxWorkers=2 — VERDICT command-exit 0; \"Test Files 26 passed (26)\", \"Tests 364 passed (364)\". pnpm --filter @objectstack/example-showcase validate — VERDICT command-exit 0. pnpm lint (eslint . --no-inline-config, WHOLE REPO, not narrowed) — VERDICT command-exit 0 in 74s. Derived union: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack with no paths, run after the final commit; it derived its own change set (1 path) at e9c424e79 and emitted 17 commands. 15 exit 0, plus pnpm check:nul-bytes exit 0. TWO are NOT MEASURED locally, by their own exit code 3 and their own printed verdict, not red: check-test-completeness (\"the local reading for this gate is NOT MEASURED ... it is not a red\" — it grades a saved turbo test log CI tees for it) and check:dual-build-cjs-loads (\"PREREQUISITE NOT MET ... this is NOT a pass: nothing was measured\" — 8 packages outside this card's closure have no dist/). ABLATION (reverse verification), run from COMMITTED state with a trap 'git checkout HEAD -- ABSOLUTE_PATH' on EXIT INT TERM. Rebuild leg: no rebuild sits between the edit and the instrument for the mutated file — examples/app-showcase resolves through \"main\": \"./objectstack.config.ts\", i.e. TS SOURCE, with no dist/ in the path; the dependency closure (including @objectstack/lint, which owns the rule) was built beforehand and untouched by either leg, so both legs read the same built rule code and differing source. Mutation confirmed ON DISK, not by an editor exit code: git restore --source=HEAD~1 wrote blob 106da8fa7 against the HEAD blob 76120013c, with occurrence counts of BOTH texts checked — injected/fixed text 0 occurrences, removed/pre-fix text 1 occurrence — and the run aborts if either count or the hash comparison disagrees. Ablation result, direction as predicted (diagnostic disappears): pre-fix objectstack lint = 413 warning(s), 26 suggestion(s) with exactly 1 relationship/master-detail-required — \"master_detail \\\"showcase_field_zoo.f_master_detail\\\" -> showcase_project should be required\" at objects[9].fields.f_master_detail.required; post-fix = 412 warning(s), 26 suggestion(s), 0 hits. Delta exactly minus one, exactly that rule, exactly that field. A first ablation attempt used objectstack validate as the instrument and measured NO change (33 warnings both trees, diff empty). Reporting that rather than dropping it: it is what proved validate never runs this rule and sent me to objectstack lint. RESTORE leg proved, not assumed: git checkout HEAD -- (absolute path, not a bare git checkout -- which reads the index), then git diff HEAD empty, git status --porcelain empty, and working-tree hash 76120013c equal to the HEAD blob 76120013c. Final tree is clean at e9c424e79 and origin matches.",
      "mcp_calls": "0 — all GitHub reads and writes went through authenticated REST (curl) and local git; no MCP GitHub tool was called for the whole run.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. claude commented on Sep 2, 2026

    @claude
    Contributor

    ACCEPT — PR #14449 (head e9c424e7), reviewed against GitHub, not the report.

    • Diff is the one line the card names: required: true on f_master_detail in examples/app-showcase/src/data/objects/field-zoo.object.ts, spelled like the sibling declarations. Governed-surface test 0 of 1; trial merge against origin/main CLEAN.
    • Premise re-measured, not recalled: seven Field.masterDetail() declarations across the loadable authored corpora, exactly one without required: true (this one); the bare type: 'master_detail' spelling has no hits, so the builder scan is the whole population. Both seed rows already carry the value (seed/index.ts rows 338 and 351), so no data moves.
    • Evidence beyond a green run: the ablation with objectstack lint as the instrument reads 413 → 412 warnings, the delta being exactly relationship/master-detail-required on exactly this field; the first attempt with objectstack validate measured no change (33 warnings both trees), which is the correct reading — that command never runs this rule. The pushed commit message names validate; the PR body carries the correction and is what the squash carries, so the wrong name does not reach main.
    • Changeset routing: @objectstack/example-showcase is private: true ⇒ skip-changeset, matching precedent (fix(examples): correct f_address seed key to postalCode #14090). The contract-doc gap the dev flagged (the os-dev skip-changeset closed list does not enumerate examples/** although its criterion covers it) is a skills-lane finding, filed separately by this seat.
    • Observed and left unchanged, as the dev reported: objectstack validate warns on both trees that showcase_field_zoo is a detail object with no object-level CRUD grant in any permission set — pre-existing, not this PR's; filed separately for triage.
    • Clause ②: no (example corpus hygiene; no contract surface). Served reviewer string for the record: claude-fable-5-1.

    Landing: ready + auto-merge (squash) once every check on e9c424e7 is green.


    Generated by Claude Code

  7. claude commented on Sep 2, 2026

    @claude
    Contributor

    CI red on PR #14449 head e9c424e7 — this PR's own; patch round dispatched.

    • Failing check: Dogfood Regression Gate (2/3) (run 33603420183). Signature: packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts:90 — write f_time hm: expected 400 to be 201, preceded in the engine log by Insert operation failed {"object":"showcase_field_zoo","error":{"message":"Master-Detail → Project is required"}}. Every other suite in the shard passed (42 files / 280 tests).
    • Not base-red: the same check is success on the last five origin/main commits (through a98b61b3).
    • Reading: the card's premise that both seed rows comply was true and is not the whole population — the dogfood suite creates showcase_field_zoo rows with only the field under test, which the newly required master now refuses. That is the required flag doing its job at a consumer that never supplied a master; the consumer is fixed in this PR (every zoo insert in packages/qa/dogfood gets a valid showcase_project master), not the flag weakened. The file-surface increase into packages/qa/dogfood/** is declared by the dev's amendment comment; the ACCEPT above stands, landing waits for green on the patched head.
    • Side reading from the same build log, filed separately as finding(showcase): seven showcase objects are exposed in navigation with no permission set granting read, and showcase_field_zoo is a detail object with no CRUD grant — the showcase build warns on every run #14453: seven showcase objects are exposed in navigation with no permission set granting read, and showcase_field_zoo is a detail object with no CRUD grant (rule security-master-detail-ungranted) — pre-existing, identical on main, not this PR's.

    Generated by Claude Code

  8. claude commented on Sep 2, 2026

    @claude
    Contributor

    Amendment to the claim above (same session session_01GDA48PuRFrHyRfdkBz8m21, same branch claude/issue-13723-field-zoo-master-detail-required, PR #14449).

    The card's "turns nothing red" clause was wrong, and CI found the consumer it missed. Dogfood Regression Gate (2/3) failed on my head e9c424e7 in packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts:90 — write f_time hm: expected 400 to be 201, with the engine log above it reading Insert operation failed {"object":"showcase_field_zoo","error":{"message":"Master-Detail → Project is required"}}. That suite creates showcase_field_zoo rows with no f_master_detail; making the field required is what refuses them.

    Declaring the widened file surface, since it reaches into another lane's package:

    • packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts — the four zoo inserts now carry a real master, and the file seeds its own showcase_account + showcase_project in beforeAll to supply one. Also corrects a comment in that file that claimed the object "requires only name".

    No other writer needed touching: field-zoo-roundtrip.dogfood.test.ts already seeds f_master_detail from REFERENCE_TARGETS, and action-params-contract.dogfood.test.ts only invokes actions. Swept the tree for every other showcase_field_zoo reference; the remainder are name-list assertions, comments and a read-only page visit.

    The field stays required: true — no test was skipped, quarantined or weakened. skip-changeset stays correct: @objectstack/dogfood is "private": true as well.

    Generated by Claude Code


    Generated by Claude Code

  9. claude commented on Sep 2, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13723,
      "status": "done",
      "branch": "claude/issue-13723-field-zoo-master-detail-required",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14449",
      "head": "b0e788ee3",
      "premise_still_valid": true,
      "summary": "PATCH ROUND. The card's PRIMARY premise held and still holds: field-zoo.object.ts:107 really was the only master_detail in the authored corpora without required:true (7 declarations, 1 missing), and the fix is one line. The card's COLLATERAL clause — \"seed rows already comply, so it turns nothing red\" — was FALSE, and CI caught it: Dogfood Regression Gate (2/3) failed on head e9c424e7 at packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts:90, \"write f_time hm: expected 400 to be 201\", engine log \"Insert operation failed {object: showcase_field_zoo, error: Master-Detail → Project is required}\". Why my own census missed it, stated plainly because it is the transferable lesson: I measured DECLARATIONS (which objects declare a master_detail without required) and the seed ROWS. Neither question can see a third population — other suites that WRITE zoo records. temporal-storage-e2e creates its fixtures through the real REST path with only name plus a temporal field, on the strength of a comment in that file asserting the object \"requires only name\". A declaration census cannot answer \"who inserts rows into this object\"; that needed its own grep and did not get one. Fix: merged origin/main first (clean, no deferred regen), then made the dogfood suite seed its own master chain in beforeAll — showcase_account, then showcase_project (which declares a required lookup to the account, so the order is forced) — and passed that id to all four zoo inserts, including the epoch-rejection case so its asserted 400 is still about f_time and not a missing master. Created rather than read out of the showcase seed on purpose: that file's assertions depend on it owning every row it reads. Also corrected the stale \"requires only name\" comment. The field stays required: true; nothing was skipped, quarantined or weakened. Widened file surface declared in a separate amendment comment on this card, and in a new \"Consumer fix\" section of the PR body: one file, packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts. Swept the whole tree for showcase_field_zoo — field-zoo-roundtrip.dogfood.test.ts already resolves f_master_detail via REFERENCE_TARGETS (why it stayed green), action-params-contract only invokes actions, and everything else is name-list assertions, comments and one read-only page visit. The unsharded full-suite run below confirms that sweep empirically rather than by argument. skip-changeset stays correct and is still on the PR: @objectstack/dogfood is \"private\": true, same as example-showcase. No label was touched this round; size/s and tests were added by the labeler.",
      "tests": "All heavy commands via scripts/pm/os-verify-lock.sh (slot issue-13723), exit codes captured before any pipe, verdicts read from the printed VERDICT line. Dependency closure rebuilt after the merge: pnpm --filter '@objectstack/dogfood^...' build — VERDICT command-exit 0, zero error lines. REPRODUCE-THEN-PROVE, from COMMITTED state with a trap 'git checkout HEAD -- ABSOLUTE_PATH' on EXIT INT TERM. Mutation (restoring the pre-fix dogfood file, i.e. the exact tree CI reddened) confirmed ON DISK before measuring: git restore --source=HEAD~1 wrote blob b0790b8ea against the HEAD blob 922bc1339, with occurrence counts of BOTH texts checked (\"f_master_detail: masterId\" 0, stale comment 1); the script aborts if either count or the hash comparison disagrees. PRE-FIX run: pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/temporal-storage-e2e.dogfood.test.ts — VERDICT command-exit 1, reproducing CI exactly: \"AssertionError: write f_time hm: expected 400 to be 201\" with the identical engine log \"Insert operation failed {\\\"object\\\":\\\"showcase_field_zoo\\\",\\\"error\\\":{\\\"message\\\":\\\"Master-Detail → Project is required\\\"}}\" from validateRecord; Test Files 1 failed (1), Tests 8 skipped (8). RESTORE leg proved, not assumed: git checkout HEAD -- (absolute path, never a bare git checkout -- which reads the index), then git diff HEAD empty, git status --porcelain empty, working-tree hash 922bc1339 equal to the HEAD blob 922bc1339. POST-FIX run, same command: VERDICT command-exit 0 — Test Files 1 passed (1), Tests 8 passed (8). WHOLE dogfood suite, UNSHARDED (the check that no other consumer was missed): pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 — VERDICT command-exit 0, Test Files 129 passed | 1 skipped (130), Tests 1003 passed | 3 skipped (1006). Held the shared lock 436s (7m16s); flagging the hold since it is long for this box. pnpm --filter @objectstack/dogfood typecheck exit 0 · pnpm --filter @objectstack/example-showcase typecheck exit 0 · showcase suite vitest run --maxWorkers=2 exit 0 (26 files, 364 tests) · pnpm --filter @objectstack/example-showcase validate exit 0 · pnpm lint (eslint . --no-inline-config, WHOLE REPO, not narrowed) VERDICT command-exit 0 in 68s. Derived union re-run on the FINAL head: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, deriving its own change set — 2 paths at b0e788ee3, 32 commands (up from 17 before the dogfood path joined; merge base moved to a98b61b3e). 30 exit 0 plus pnpm check:nul-bytes exit 0, including the newly-pulled-in families check:engine-double-contract, check:shard-attestation, check:plugin-teardown-shape, check:query-options-erasure, check:slot-lookup, check:where-matcher, check:objectql-double-limit, check:doc-authoring, check:type-check-coverage, check:type-check-debt, the four spec check:* and the two docs-audit scripts. The SAME two are NOT MEASURED locally rather than green, by their own exit code 3 and their own printed verdict, unchanged from round one: check-test-completeness (\"the local reading for this gate is NOT MEASURED ... it is not a red\" — it grades a saved turbo test log CI tees for it) and check:dual-build-cjs-loads (\"PREREQUISITE NOT MET ... this is NOT a pass: nothing was measured\" — 8 packages outside this card's closure have no dist/). Final tree clean at b0e788ee3, origin in sync, PR still draft, auto-merge never armed.",
      "mcp_calls": "0 — all GitHub reads and writes went through authenticated REST (curl) and local git across both rounds; no MCP GitHub tool was called.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  10. claude commented on Sep 2, 2026

    @claude
    Contributor

    Patch round reviewed — PR #14449 head b0e788ee (one commit on top of the accepted e9c424e7, plus the merge of origin/main).

    • Verified against the diff: one consumer file, packages/qa/dogfood/test/temporal-storage-e2e.dogfood.test.ts — the suite now seeds its own showcase_account → showcase_project chain in beforeAll (the forced order, since the project declares a required lookup to the account) and passes that master to all four zoo inserts, including the epoch-rejection case so its asserted 400 stays about f_time. The stale "requires only name" comment is corrected. The field stays required: true; nothing skipped, quarantined or weakened.
    • Red reproduced before the fix with CI's exact signature (write f_time hm: expected 400 to be 201, engine log Master-Detail → Project is required), green after; the whole dogfood suite run unsharded (129 files / 1003 tests) is the empirical form of the writer sweep. CI on b0e788ee: every check green, all three Dogfood shards success.
    • The transferable lesson the dev states is the right one and is recorded here for the census discipline: a declaration census and a seed-row census cannot see a third population — other suites that WRITE rows into the object; "turns nothing red" needs its own grep of writers, which the card's premise never had.
    • File-surface increase into packages/qa/dogfood/** declared (amendment 5506477506) and in the PR body's Consumer fix section; @objectstack/dogfood is private: true, so skip-changeset stays correct. Pre-flip reads on b0e788ee: governed-surface test 0 of 2, trial merge against origin/main (1d8ad0ff) CLEAN, main has not moved on its files, first line Fixes #13723 with no other closing keyword. The ACCEPT above stands unchanged.

    Ready + auto-merge (squash) now.


    Generated by Claude Code

  11. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationdomain:specDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions