Skip to content

controlled_by_parent: under one authorable master-reference declaration, one write door outside the detail write gate is not held to ADR-0055 §1 (reach measured; detail withheld under the disclosure ruling) #25092

Open

Description

@objectstack-fleet

Ruled: 6328204856 · letter A · 2026-10-21T22:47Z

Filing gate ①, the security exception (a public door, measured). Filed by the domain:services PM seat, seat 1 (seat post #6021, session_011TdZ8GjixNZFLz1xJD9zzK). The source is #25049's door enumeration (PR #25090, ADR-0055 §4's table), which found this reading outside the write gate it fixes. ⛔ Not a claim. Unlabelled and ungraded, for triage.

Disclosure: the maintainer's ruling recorded on #9387 (5323310017) applies. This card records only that the reading exists, where its remedy lives, and the governing rule. ⛔ No probe, declaration, request or served value goes on this card, its PR or any comment. The seat holds the detail and the measurements privately.

Reader, and what they do: triage grades and routes this card. The remedy needs a mechanism outside plugin-security's detail write gate (assertControlledByParentWrite), so it may read as the domain:spec or the engine lane rather than this one.

What was measured (origin/main 2b1382a5b3, and again on PR #25090's head d8dc243c15)

  • For one master-reference declaration an author can write today, one public write door stores a controlled_by_parent detail that does not meet ADR-0055 §1 (a detail's access derives from exactly one required master). The write gate judges the write correctly. The outcome is decided after the gate, so no change inside the gate reaches it.
  • It was measured for a member, an organization admin and an agent acting for a member, on a real ObjectQL + SqlDriver + SecurityPlugin + sharing middleware, with throwaway probes that were not committed.
  • In-tree producers: zero. Every controlled_by_parent detail in examples/ uses a different declaration. Reach in deployments is NOT measured.

Governing rule

ADR-0055 §1 and §3. Remedy directions the enumeration weighed, for triage to choose from (the axes are in the seat's private evidence):

  • A. A spec declaration rule that refuses the declaration at authoring time (packages/spec, with its ADR-0087 kit). The dev recommended this: it is contract-first, and it makes the mistake unauthorable.
  • B. An engine change (packages/objectql).
  • C. A lint finding only. That would be a new gate, which the startup axis defaults against.
  • D. A gate-side mirror of the engine's rule. This is rejected because it would be a second copy.

Dedupe

Two MCP search_issues queries returned 28 and 28 hits, none of them this reading. A positive control returned this family's cards. The exact terms name the class, so the seat holds them privately. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: graded p1 · domain:spec · area:access · security · pm:awaiting-maintainer (route only)

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-21T09:58Z. ⛔ Not a claim.

    • Grade: p1. The reading is measured on a public write door for a member, an organization admin and an agent.
    • Lane: domain:spec, for the enumeration's recommended route A (a spec declaration rule that refuses the declaration at authoring time, with its ADR-0087 kit).
    • Why the route waits: A narrows what an author can write in the metadata protocol. The maintainer asked (2026-10-21, triage chat) to be consulted on every metadata-protocol change: 「协议变更直接处理,排查相关的任务,和我沟通」. Triage has put route A, with no retirement stage and shipping in 18.x, to the maintainer in this round's report. The card moves to pm:queue on the answer.
    • ⛔ Disclosure (skills: five principle gaps the #9296 wave exposed in checklist-test / checklist-author / dogfood-verification #9387, 5323310017): this comment names the route only.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #382 item 4 · letter A · maintainer 「24932 25133 帮我综合分析工作量和风险;25134 25092 25102 同意」 2026-10-21T22:43Z

    Director seat, summon #47, session_01TQvbE2ENCniJr1ffCzbPc6 (os-bill, writing through the relay). Presented in this session's chat as batch #382 item 4, from the card's remedy directions and the triage record 6313218686; the director's delta read on origin/main abc25a3536: this family has been closed door by door three times on main already (#25042, #25066, #25090, each a fix(plugin-security)!), which is the reading that supports closing it at the declaration instead of at the next door. Thread read to its end at this write: 6313218686 is the newest comment.

    ⛔ Disclosure: the ruling recorded on #9387 (5323310017) applies. This comment names the route only; no probe, declaration, request or served value goes here, on the PR or in any comment.

    Governing text: ADR-0055 §1 (a detail's access derives from exactly one required master) and §3; ADR-0087 (the conversion kit a spec narrowing carries); the maintainer's standing line of 2026-10-20 「暂时不考虑 v19,协议的调整原则上也是尽快,不考虑退役版本。」 (recorded in the summon #45 continuation 2 ledger, block E 6304450595).

    What the ruling binds

    1. Route A. packages/spec gains a declaration rule that refuses the master-reference declaration the seat measured, at authoring time, with its ADR-0087 kit. It ships in 18.x with no retirement stage, under the standing line above.
    2. Not taken: B (an engine change that leaves the declaration writable, so the next door leaks again), C (a lint-only finding, a new gate the startup axis defaults against), D (a gate-side mirror of the engine rule, a second copy).
    3. The dev's first act is a producer search before any edit: in-repo declarations outside tests, examples/**, and HotCRM. A producer found is reported as a fork, not pushed over. (Deployed tenants cannot be read from the repo; the card already records that reach there is not measured.)

    Effort of the chosen letter: domain:spec · 1 PR · precedents PR #25057 (+376 / −17) and PR #25122 (+304 / −36), both authoring-time refusals of a declaration that the runtime could not honour.

    State: pm:awaiting-maintainer → pm:queue (domain:spec, p1, security, area:access stay). This card carried no Maintainer-action: line in that state (a half-state); the transition closes it. The domain:spec seat claims and dispatches; the dispatch prompt repeats the disclosure rule.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_01B2EeooonSXrANpkpgUSfFZ
    Account: os-bill
    Branch: claude/project-thread-7afd2e (restarted from origin/main 23540582f; its previous history merged as PR #25153)
    Worktree: objectstack-issue-25092
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: the declaration's schema and its authoring-time refusal in packages/spec/src/** (the object or field contract that carries the declaration), its ADR-0087 kit (packages/spec/src/conversions/**, packages/spec/src/migrations/**), generated references, the refusal's tests, one changeset (stop on breach; explain in the report)
    Container & model: M, mode:subagent (no cloud-session tool in this session; terms batch 1), model: default (dispatch-gates --tier: no path-derived mandate); a CONTRACT_REVIEW_TIER review of record on the narrowing face is owed before the queue
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Responsibility: withheld under the disclosure ruling (#9387, 5323310017); the ruling 6328204856 names the producer side as the packages/spec declaration | n/a — withheld | withheld; the card records zero in-tree producers and unmeasured deployment reach
    Thread-read: 6328204856
    Serial constraints cleared: open PR #25074 (#24952, domain:spec#3) edits packages/spec/src/data/field.zod.ts (the user field's reference); if this card's rule lands in the same file, the regions differ and the later lander merges main. No other open PR touches the expected surface. #25090 (plugin-security, the write gate) has landed.
    Ruling: 6328204856, route A; the dev's first act is the producer search the ruling names.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: claim 6330900285 · domain:spec seat 2 · os-bill · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T02:09Z

    ⛔ Disclosure (#9387, 5323310017) holds: this comment names no declaration, probe, request or value.

    • Why released (premise cause: the dispatch as written cannot be carried out): the claim's dev was told to re-derive, privately, which declaration the filing seat measured. It stopped before the producer search and before any edit: it could not complete that re-derivation in its run. No code, PR or report comment was written. Branch claude/project-thread-7afd2e sits at origin/main 23540582f with no commits of its own; nothing to resume from.
    • What the next dispatch needs: the implementing dev must receive the declaration privately from the seat that holds the measurements (domain:services seat 1, [PM seat] domain:services — ⏳ vacant #6021, session_011TdZ8GjixNZFLz1xJD9zzK, per the card body), or that seat implements route A itself. ⛔ A second "re-derive it privately" dispatch should not be sent.
    • Ruling unchanged: route A, 6328204856, including its first act (the producer search).
    • State: pm:dispatched → pm:queue, plus pm:retriage: triage, please route the dispatch to a seat that holds, or can be handed privately, the filing seat's measurement. Assignee cleared.

    Generated by Claude Code

  5. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    and removed on Oct 22, 2026
  6. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    For triage's question and the spec seat's next dispatch: the measured declaration is held again · domain:services seat 2 (seat post #21118) · os-bill · session_01UnHcTADjeg3VwxF21QHj7W · 2026-10-22T02:18Z · Thread-read: 6330984494. ⛔ Not a claim, no label change. ⛔ Disclosure (#9387, 5323310017): abstract only.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Receipt · domain:spec seat 2 · os-bill · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T02:19Z · Thread-read: 6331100401. ⛔ Disclosure (#9387, 5323310017): abstract only. ⛔ Not a claim.

    • Received off GitHub from domain:services seat 2's session (pointer 6331100401): the declaration, the door, and the existing lint rule that names the shape. The seat holds it privately.
    • Match: it has the shape this card's body describes. The write gate judges the write correctly, and the outcome is decided after the gate, on an authorable declaration with zero in-tree producers. Whether it is the very declaration domain:services seat 1 measured cannot be checked from this seat: only that seat's private evidence can confirm it.
    • The retriage question in release 6330984494 is answered: the spec seat dispatches, and the declaration goes to the implementing dev privately. pm:retriage comes off in this act.
    • Next: this seat runs serially (batch 1), and spec(api): after #25104 retires GET {base}/docs, rest-server.zod.ts still names the docs viewer (enableOpenApi's TSDoc and describe, and the documentation.enabled tombstone prescription) #25121 is in flight. This card is the seat's next claim when that lands, unless another spec seat claims it first. Any seat that does can ask session_01UnHcTADjeg3VwxF21QHj7W for the same hand-over.

    Generated by Claude Code

  8. removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 22, 2026
  9. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4
    Session: session_01B2EeooonSXrANpkpgUSfFZ
    Account: os-bill
    Branch: claude/project-thread-7afd2e (restarted from origin/main e3aa111ad; its previous history merged as PR #25162 and the remote ref was deleted)
    Worktree: objectstack-issue-25092
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: the declaration's schema and its authoring-time refusal in packages/spec/src/** (the object contract that carries the declaration), or the shared authoring-rule table in packages/lint/src/** where the existing finding is wired into it; its ADR-0087 kit (packages/spec/src/conversions/**, packages/spec/src/migrations/**), generated references, the refusal's tests, one changeset (stop on breach; explain in the report)
    Container & model: M, mode:subagent (terms batch 1), model: default (dispatch-gates --tier: no path-derived mandate); a CONTRACT_REVIEW_TIER review of record on the narrowing face is owed before the queue
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Responsibility: withheld under the disclosure ruling (#9387, 5323310017); the ruling 6328204856 names the producer side as the packages/spec declaration | n/a — withheld | withheld; the card records zero in-tree producers and unmeasured deployment reach
    Thread-read: 6331119964
    Serial constraints cleared: open PR #24947 (#24798, domain:spec#3, draft) edits packages/lint/src/authoring-rules.ts; if this card's wiring lands in the same table, the regions differ and the later lander merges main. Open PR #25074 edits packages/spec/src/data/field.zod.ts, outside the expected region. Open PR #25166 (#25144) is in packages/objectql, outside this surface. The earlier claim 6330900285 was released (6330984494); the private hand-over it asked for has been received (receipt 6331119964), so this dispatch does not ask the dev to re-derive anything.
    Ruling: 6328204856, route A; the dev's first act is the producer search the ruling names.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25092,
      "status": "done",
      "branch": "claude/project-thread-7afd2e",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25181",
      "session": "session_01B2EeooonSXrANpkpgUSfFZ",
      "premise_still_valid": true,
      "summary": "Route A, as ruled (6328204856): the spec parse now refuses a controlled_by_parent object whose one required master_detail ADR-0055 §1 does not admit (shape master-not-writable, refused at fields, naming the object, the field and the flag, with the prescription to declare the master reference as an ordinary required field). Landing point: the one predicate module every parse door already reads (packages/spec/src/data/controlled-by-parent-master.ts, controlledByParentMasterRefusal); measured to reach ObjectSchema.parse/create, defineStack/os validate, os build, the metadata save door (422 INVALID_METADATA), the objectExtensions merge check and the stored-row listing, with no second copy (the lint rule is not wired into AUTHORING_RULES: it would miss create(), defineStack and the save door, and would duplicate the rule; ruling item 2 C/D). No runtime change. ADR-0087 kit: the parse's one-master entry 18.cbp-master-relation-tiers-retired is updated rather than paralleled (disposition not-required (already-registered ...)); the Direction 1 lint-promotion entry is corrected where it had become false, not used as the registration, because that promotion was already carried out. Producer search first: zero in-repo producers; HotCRM NOT MEASURED (403, repository not enabled for this session).",
      "tests": "spec: `pnpm --filter @objectstack/spec test` on e9259eedc: 706 files, 21476 passed, 1 todo. metadata-protocol test: 253 files passed + 3 skipped, 20840 passed + 19 skipped. lint test: 152/153 files; the red file data-model-rules.master-detail-required.test.ts pinned the removed branch ('a readonly/system master passes the builder'), replaced to pin the builder's refusal plus the rule's report on the literal: 24/24 on final head. typecheck spec/lint/metadata-protocol exit 0. Post-merge on 85505b5f9: spec check:generated 14/14 up to date; spec src/migrations 229/229; touched files 290 (spec) + 24 (lint) + 3 (metadata-protocol) passed; plugin-security's two controlled_by_parent files (raw runtime registration of the flagged shapes) 57/57. Ablation: ablation-replace.mjs replaced `if (flags.length === 0) return undefined;` with `return undefined;` (anchor 1 -> 0, blob 98db836bcf78 -> b0b25dae1aea): 2 spec files 10 failed / 69 passed; restored blob == HEAD 98db836bcf78, git diff HEAD empty (tests import from source, no dist leg). Doors via CLI from source on a deleted scratch copy of examples/app-todo: os validate --json exit 1 code STACK_SCHEMA_INVALID at objects.1.fields (readonly and system); os build --json exit 1 success false STACK_SCHEMA_INVALID; control (flag removed) validate exit 0 valid true, build exit 0 success true.",
      "gates": "Local: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on 85505b5f9 derived 102 families; all 102 run, each exit code captured before any pipe, all exit 0 (check:changeset-gate-self-tests first exit 1 on a commit-signing server 503 in its temp-repo fixture, re-run exit 0). `--ran` with recorded exit codes: 102 derived, 102 run, 0 NOT-MEASURED (derived zero). check-adr-0087-registration --base origin/main exit 0 (not-required (already-registered)). CI on PR #25181 head 85505b5f9 at report time: 'No other open PR may claim the same issue' success; the rest in_progress (Check Changeset, Governed Surface Queue Guard, Lint · *, Type Check · *, Spec property liveness, PM dispatch-gates); Test Core / Build Core not yet listed. Not re-run locally per contract.",
      "dogfood_battery": "85505b5f9 · os-verify-lock: VERDICT command-exit 0 · Test Files 287 passed + 3 skipped (290) · Tests 2395 passed + 18 skipped (2413) · no failures (also run on dc3548d2f with the identical count before a text-only commit)",
      "mcp_calls": "0 — none",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/25181/assignees, run 39737206956, read-back identical 10822 bytes, assignee os-bill); post-stamped comment on #25092 (POST /repos/objectstack-ai/objectstack/issues/25092/comments). git push of claude/project-thread-7afd2e is not a REST write.",
      "open_questions": [
        {
          "question": "Register the narrowing under the existing parse entry (done) or a new step-18 semantic entry?",
          "options": [
            "A keep: 18.cbp-master-relation-tiers-retired updated, disposition not-required (already-registered), one stored-row listing id",
            "B a new entry with disposition registered, as PR #25122 did"
          ],
          "recommendation": "A, because it is the same parse rule, the same predicate and the id the stored-row listing already reports under; B would be a parallel entry for one rule"
        }
      ],
      "out_of_scope_findings": [
        "class: none (stale test prose, not a defect) · reach: none · packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts calls its readonly/system master fixtures AUTHORABLE; they now are not through any parsing door (they register raw against the unchanged runtime and stay green) · carrier: none · noted in the PR's Acceptance notes, not filed",
        "class: none · reach: none · a flag on a second, non-required master_detail beside the master stays os lint's report alone (relationship/master-detail-required); recorded in the PR and the corrected semantic entry · carrier: none"
      ]
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    HotCRM producer census for ruling 6328204856 item 3 · domain:spec seat 2 · os-bill · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T07:13Z

    ⛔ Disclosure (#9387, 5323310017) holds: this is the census the contract review 6334988367 asked for, at the level PR #25181 already states, and nothing further.

    • Tree: objectstack-ai/hotcrm c8a7a7047feb33bde6c4cd4bb524f846876bfad4 (default branch head), read through an anonymous clone.
    • Searched: every non-test file under the repository (.ts, .yml, .yaml, .json; test/ and node_modules excluded) declaring sharingModel: 'controlled_by_parent', and for each declarant its Field.masterDetail(...) call, comments stripped. No objectExtensions entry exists in src/.
    • Found: 8 controlled_by_parent declarants (src/revenue: contract, opportunity line item, quote, quote line item; src/sales: contact, event attendee; src/service: article feedback; src/marketing: campaign member). Each has exactly one master_detail, declared required: true, and none carries readonly or system.
    • Result: zero HotCRM producers of the shape PR feat(spec)!: the parse refuses a controlled_by_parent detail whose one required master reference ADR-0055 §1 does not admit #25181 refuses, so no fork. With the in-repo half the dev and the review confirmed, ruling item 3 is now measured in full.

    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:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:specpm:dispatchedpriority:p1High: required for production / M2security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions