Skip to content

finding(security): an objectExtensions entry that adds a second required master_detail to a controlled_by_parent object passes defineStack and the posture lint, then fails closed at runtime — neither door judges the merged shape #23210

Closed

Description

@objectstack-fleet

Filing gate: (c) a trap that lets an author, or an AI, write metadata the runtime refuses. reach: the authoring doors defineStack and the security-posture rules that os validate runs, on the published objectExtensions surface (examples/app-showcase authors it). Measured by probes against source at PR #23179's head 6582c1f0d (dev report 6141838120 on #23100, out-of-scope finding 1). No measured producer writes the trap shape today: HotCRM at 0f84c9c declares no objectExtensions, and the showcase's entries add no master_detail. Reader who acts: triage, to grade and route (packages/spec and packages/lint are both domain:spec); then the owning seat.

Filed by domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H. ⛔ Not a claim.

What happens

The stack, in short:

  • objects: cbpx_header, cbpx_other, and cbpx_line with sharingModel: 'controlled_by_parent' and one required master_detail field header pointing at cbpx_header.
  • objectExtensions: [{ extend: 'cbpx_line', fields: { other: { type: 'master_detail', reference: 'cbpx_other', required: true } } }].

Measured at 6582c1f0d:

  • defineStack returns clean, and ObjectStackDefinitionSchema.safeParse succeeds.
  • validateSecurityPosture (packages/lint) returns no controlled-by-parent finding.
  • At boot the merge gives cbpx_line two required master_detail fields. With PR feat(spec)!: a controlled_by_parent object derives its master from exactly one required master_detail; the runtime's fallback tiers retire (#23100) #23179 the runtime derives no master from that shape. Every read is denied, every write answers 422 INVALID_METADATA, and the only signal is the once-per-object warn.
  • Control: the same merged object declared as one object is refused by defineStack (objects.2.fields: … with 2 required master_detail fields (header, other)) and by the lint (security-controlled-by-parent-ambiguous-relation).

So the extension door carries a shape that both authoring doors refuse when it is written directly. On main without PR #23179, the runtime instead picks one of the two by field order, the tier that PR retires. That consequence was read from code, not measured.

Where

  • The merge runs only at boot: packages/objectql/src/engine.ts (:7487–:7489 on origin/main at 150da61aa) registers each manifest.objectExtensions entry onto its target.
  • packages/lint/src/validate-security-posture.ts and packages/cli/src/commands/validate.ts never read objectExtensions (git grep -c on origin/main: 0 hits in each).
  • Sibling lint rules already treat extensions as a blind spot by design. validate-object-references.ts:293 says "objectExtensions[].fields is deliberately NOT walked", and validate-field-consumers.ts:167 says object extensions "are not judged". An extension usually targets an object another package owns, which the stack in hand cannot see. In this case the target is in the same stack.

Acceptance

  • When an objectExtensions entry's target is visible to the door (declared in the same stack, or in a packages[] manifest the door already folds), the controlled-by-parent master rule judges the merged field set. A controlled_by_parent object that ends up with anything but exactly one required master_detail is refused at the same door, with the same issue, as the directly declared shape.
  • A target that the door cannot see stays unjudged, as today. The runtime's fail-closed refusal and its warn remain the backstop.
  • Pins: the probe stack above is refused, and its control is unchanged. A routing alternative is for the extension schema to refuse a master_detail field onto any target. That changes the published surface, and triage or the owning seat decides it.

Dedupe

MCP search_issues on objectstack-ai/objectstack, closed included:

None is this. Control: the queries reach the controlled-by-parent family (#7503, #9139) and the extension-merge family (#8027).

Dedupe words: controlled_by_parent objectExtensions second master_detail; extension merged field set sharingModel parse; posture lint objectExtensions blind.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · domain:spec · area:access, into pm:queue. The door judges the merged shape when it can see the target

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T09:55Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Regrade: p3 → p1 · target:v18 added · a metadata-protocol narrowing · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T07:14Z

    Why it moves: the maintainer directed, on 2026-10-14, that spec-lane queue cards which change the metadata protocol (what @objectstack/spec accepts or declares, or what a metadata door accepts) be raised. The bar triage now applies: a protocol change gets target:v18, so it lands in the 18 window and objectui, cloud and HotCRM mirror it once. A narrowing (breaking) one is p1, because missing 18 GA means waiting for 19. A widening (additive) one is at least p2.

    Read fresh. On main b5b1bf7277, packages/spec/src/stack.zod.ts still has no refinement that judges an objectExtensions entry against its controlled_by_parent target.

    • What changes: ObjectStackDefinitionSchema (defineStack) starts refusing a stack whose objectExtensions add a second required master_detail to a controlled_by_parent object. That narrows a published accept set: breaking, with an ADR-0087 entry, and it must ride the 18 major.
    • What does not change: the direction in my first grade (the door judges the merged shape when it can see the target). The runtime already fails closed, so this is the authoring door catching up.
    • Clause ②: narrowing, so no, and it owes the contract-tier review.
  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (#23210, triage 6142996061 and regrade 6163015687: when an objectExtensions entry's target is visible to the door, defineStack's refinement and the os validate posture lint judge the merged field set under the controlled-by-parent master rule; a narrowing, target:v18) · 2026-10-14T07:38Z
    Session: session_01YRp5z4kK6vgYkrdH97ztsy
    Account: huangyiirene (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23210-extension-master-detail
    Worktree: objectstack-issue-23210
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main b5b1bf727 or later; stop on a breach and explain it in the report):

    • The stack door: packages/spec/src/stack.zod.ts, a refinement that judges each objectExtensions entry whose target the stack can see against the merged field set. It reuses controlledByParentMasterRefusal (packages/spec/src/data/controlled-by-parent-master.ts) and its message rather than copying either. That file is edited only if the merged-shape call needs a signature it lacks.
    • The lint door: packages/lint/src/validate-security-posture.ts (security-controlled-by-parent-ambiguous-relation on the merged shape), plus packages/cli/src/commands/validate.ts only if the lint's input measurably lacks objectExtensions.
    • One ADR-0087 entry for the narrowing under packages/spec/src/migrations/entries/** (class by census) and the registries it feeds.
    • Tests (the card's stack refused at both doors, its single-object control unchanged, a non-master field extension on a controlled object passing, an unseen-target extension unjudged), generated projections, and one .changeset/23210-*.md.
    • ⛔ Not packages/objectql/src/engine.ts (the runtime merge and its fail-closed refusal stay the backstop). ⛔ Not ObjectExtensionSchema's accept set (the routing alternative the card names; triage did not take it).
      Container & model: M, mode:subagent, model: default (dispatch-gates --tier: "no path-derived mandate … floor sonnet · default opus · ceiling fable"); the review before the queue runs at the ceiling, CONTRACT_REVIEW_TIER (reason: a narrowing of a published accept set owes one contract-tier review).
      Clause-②: no (narrowing)
      Responsibility: packages/spec's stack refinement and packages/lint's posture rules, which judge a controlled_by_parent object's masters only as declared, never as merged with a visible objectExtensions entry | the runtime merge at boot fails closed (every read denied, every write 422 INVALID_METADATA, one warn) | any author or AI extending an object in the same stack or a folded packages[] manifest; no measured producer today (HotCRM declares no objectExtensions; the showcase's add no master_detail)
      Thread-read: 6163015687
      Serial constraints cleared: open PRs' file lists read in this act. PR feat(spec)!: publish refuses an anonymous flow endpoint whose target flow runs as system, in both directions (ADR-0138 D2b) #23411 (ADR-0138 E2: the closed list of doors recorded in the conformance matrix, denial by domain, and D2b's publish refusal (D2, D2b) #23225, this seat, in the merge queue) edits stack.zod.ts around applyApiEndpointGates (imports and :167–:200), a different region; the dev syncs main after it lands. The security: externalSharingModel is declared and authored but has no runtime reader — an object's externalSharingModel: private changes no answer for any principal (ADR-0090 D11 declared-not-enforced) #23268 claim (6161609217, seat 3) holds validate-security-posture.ts for the externalSharingModel rules, a different rule. Neither is a SINGLE_CLAIM_PATHS path, so ordinary concurrency applies and the later lander merges main.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23210,
      "status": "done",
      "branch": "claude/issue-23210-extension-master-detail",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23454",
      "session": "session_01YRp5z4kK6vgYkrdH97ztsy — the dispatching PM's session (mode:subagent); every commit carries it as the Claude-Session trailer",
      "premise_still_valid": true,
      "summary": "Both authoring doors now judge ADR-0055 §1 on a controlled_by_parent object's MERGED field set when the stack declares the target. Spec side: a new superRefine, applyControlledByParentExtensionGate, on ObjectStackDefinitionSchema, chained after applyApiEndpointGates and applyPermissionSetOwnerBindingGate, calling the existing internal controlledByParentMasterRefusal. The issue sits at objectExtensions.N.fields (or packages.J.manifest.objectExtensions.N.fields) with the declared control's message byte-equal, and defineStack throws STACK_SCHEMA_INVALID/422. Lint side: validateSecurityPosture gains a merged-shape pass emitting security-controlled-by-parent-ambiguous-relation or -no-relation at the same extension, through two shared push sites so the wording is one. Visibility reading (H2/H3): exact `name` equality with `extend` (the registry keys by the string verbatim; a namespace__name spelling never merges, measured), and the artifact as the boundary. With packages[], any body's extension judges any body's object or a top-level residual object, while top-level objectExtensions are not read because the engine never registers them there. Unjudged: unseen targets, targets two bodies declare, targets already refused as declared, and two packages tied on one key at the deciding priority (registration order decides; measured). Also: a step-18 D3 entry cbp-extension-merged-master-refused (relevantWhen objectExtensions) and a BREAKING changeset with FROM→TO and the remedy. No export, signature or error code added, so Clause-② stays no (narrowing).",
      "tests": "spec unit layer (vitest --project local, 4daa50d71): Test Files 675 passed, Tests 20487 passed | 1 todo. lint full (4daa50d71): 139 files, 6718 passed. objectql unit layer (--project local, 4daa50d71): 415 files, 8087 passed. cli --project unit (4daa50d71): 285 files passed, 4278 tests passed, 29 skipped. 2 suites (published-subpath-console.pin, published-subpath-hook-body.pin) refused for want of packages/cli/dist; after `turbo run build --filter=@objectstack/cli` they ran: 2 files, 29 passed. cli integration layer declared to CI (no spawn entry or integration file touched). Typecheck: spec green at f9744329d (the later merge moved no spec source), lint green at 4daa50d71. New pins: spec stack-cbp-extension-master.test.ts 12/12 and lint validate-security-posture-extension-merge.test.ts 16/16, including an 8-shape parse-vs-lint parity table. The #5017 meta-tests in validate-security-posture.test.ts table the new reads against the live schema shapes. Ablations on the committed tree via scripts/ablation-replace.mjs (anchor must hit, blob verified, restore verified): A1 drops .superRefine(applyControlledByParentExtensionGate) (anchor 1→0, blob ecc31d4e3de3→b0e64ef6c625) and the spec pin file goes 9 failed | 3 passed (the 3 are the declared control, the already-refused object and the tie, none of which depend on the refinement); restored, blob == HEAD, git diff HEAD empty. A2 deletes the pushExtensionMergedCbpFindings call (blob 1b241d17dfd0→5a4bafa4383f) and the lint pin file goes 9 failed | 7 passed; restored and verified the same way. Both subjects resolve through source, so no dist rebuild was owed. Registry probe (scratch tsx against SchemaRegistry, not committed) for H1/H2: card shape gives master_detail=[header:true,other:true]; an extension redeclaring header required:false gives [header:false] (whole field replaced by name); sharingModel on an extend body is not carried; adder p200 + fixer p300 gives one master; p300/p200 gives two; p200/p200 is decided by the later registration; one package's two entries leave the later; an extender at p50 still folds over the owner's base; extend 'cbpx__cbpx_line' never merges into cbpx_line. H4: os validate parses (validate.ts step 2b) before the rule table, so the card's stack now stops at the parse; the rule input is the parsed union stack, which keeps objectExtensions.",
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "2 relay strokes (scripts/pm/fleet-write/dispatch.mjs, executed as objectstack-fleet[bot]): (1) pr_create, run 38545791715 = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/23454/assignees [huangyiirene]; body read back byte-identical (11521 bytes). (2) comment = POST /repos/objectstack-ai/objectstack/issues/23210/comments (this os-dev-report). Each stroke's own transport write is POST /repos/objectstack-ai/objectstack/dispatches under the session. label-write: 0, because the dispatch names no label and skip-changeset does not apply (a changeset ships). git push (not REST): the empty-branch probe plus 4 pushes, the last 4daa50d71.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — `os explain` text for security-controlled-by-parent-ambiguous-relation / -no-relation (packages/lint/src/rule-explanations.ts) still describes only the declared object, while both rules now also fire on a merged one. Outside this card's file surface; listed in the PR's Acceptance notes",
        "carrier: none · noted, not filed — validateSecurityPosture now reads stack.packages through packagesOf, so a malformed non-array packages throws INVALID_ARTIFACT_PACKAGES from this rule as its sibling readers already do. Behaviour change on an unparsed input only; listed in Acceptance notes"
      ],
      "gates": {
        "derivation": "node scripts/pm/dispatch-gates.mjs --commands at 4daa50d71: 91 families for 8 changed paths",
        "reconciliation": "dispatch-gates --ran: '✓ dispatch-gates --ran: 91 derived famil(ies) accounted for — 89 run, 2 NOT-MEASURED (1 DERIVED from a recorded exit 3, 1 claimed).'",
        "not_measured": [
          "NOT MEASURED: check:dual-build-cjs-loads, reason: exit 3 PREREQUISITE NOT MET ('Run `pnpm build` first'); only the cli dependency closure was built",
          "NOT MEASURED: type-check-debt, reason: whole-repo tsc census not run locally; owed to CI's TypeScript Type Check job"
        ],
        "local_only": [
          "pnpm check:skill-frame-freshness :: exit 0",
          "pnpm check:dev-prereqs :: exit 1, an unmet local precondition and not a verdict on this diff: 9 workspace packages outside the cli closure have no dist. spec/dist was built from this head's spec source"
        ],
        "key_verdict_lines": [
          "check-adr-0087-registration --base origin/main: '✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.' — registered cbp-extension-merged-master-refused (new here)",
          "check:api-surface: '@objectstack/spec public API surface + factory signatures unchanged ✓'",
          "spec check:generated: '✓ All 14 generated artifacts are up to date'",
          "check:nul-bytes: 'check-nul-bytes: OK (scanned 11376 text file(s) ... no raw ASCII control bytes)'",
          "check-spec-docblock-symbol-anchors: '✅ ... 0 NEW line anchors on tracked targets survive'"
        ],
        "commands": [
          "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
          "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
          "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
          "node scripts/check-changeset-no-major.mjs --self-test :: exit 0",
          "node scripts/check-ci-filter-parity.mjs :: exit 0",
          "node scripts/check-closing-keyword-parity.mjs :: exit 0",
          "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
          "node scripts/check-comment-mask-adoption.mjs :: exit 0",
          "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0",
          "node scripts/check-comment-mask-corpus.mjs :: exit 0",
          "node scripts/check-dev-prereqs.mjs --self-test :: exit 0",
          "node scripts/check-dts-emitted.mjs --self-test :: exit 0",
          "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
          "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
          "node scripts/check-issue-citations.mjs :: exit 0",
          "node scripts/check-keyed-text-bounds.mjs :: exit 0",
          "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0",
          "node scripts/check-platform-object-tenancy-census.mjs :: exit 0",
          "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0",
          "node scripts/check-plugin-teardown-shape.mjs :: exit 0",
          "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0",
          "node scripts/check-registry-log-declared.mjs :: exit 0",
          "node scripts/check-registry-log-declared.mjs --self-test :: exit 0",
          "node scripts/check-rest-log-spy-declared.mjs :: exit 0",
          "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0",
          "node scripts/check-spec-docblock-symbol-anchors.mjs :: exit 0",
          "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test :: exit 0",
          "node scripts/check-system-context-census.mjs :: exit 0",
          "node scripts/check-system-context-census.mjs --self-test :: exit 0",
          "node scripts/check-undeclared-dep-imports.mjs :: exit 0",
          "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0",
          "node scripts/docs-audit/check-affected-docs.mjs :: exit 0",
          "node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
          "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
          "node scripts/release-pending-publish.mjs --self-test :: exit 0",
          "pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0",
          "pnpm --filter @objectstack/spec run check:api-surface :: exit 0",
          "pnpm --filter @objectstack/spec run check:authorable-surface :: exit 0",
          "pnpm --filter @objectstack/spec run check:browser-reachable-entries :: exit 0",
          "pnpm --filter @objectstack/spec run check:docs :: exit 0",
          "pnpm --filter @objectstack/spec run check:dual-source-exports :: exit 0",
          "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
          "pnpm --filter @objectstack/spec run check:empty-state :: exit 0",
          "pnpm --filter @objectstack/spec run check:entry-nameability :: exit 0",
          "pnpm --filter @objectstack/spec run check:export-origins :: exit 0",
          "pnpm --filter @objectstack/spec run check:exported-any :: exit 0",
          "pnpm --filter @objectstack/spec run check:liveness :: exit 0",
          "pnpm --filter @objectstack/spec run check:llms-txt :: exit 0",
          "pnpm --filter @objectstack/spec run check:objectui-pin-citations :: exit 0",
          "pnpm --filter @objectstack/spec run check:skill-refs :: exit 0",
          "pnpm --filter @objectstack/spec run check:spec-changes :: exit 0",
          "pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0",
          "pnpm --filter @objectstack/spec run check:upgrade-guide :: exit 0",
          "pnpm --filter @objectstack/spec run check:variant-docs :: exit 0",
          "pnpm check:changeset-gate-self-tests :: exit 0",
          "pnpm check:cross-package-test-inputs :: exit 0",
          "pnpm check:dispatcher-error-vocabulary :: exit 0",
          "pnpm check:doc-authoring :: exit 0",
          "pnpm check:docs-transcript-drift :: exit 0",
          "pnpm check:driver-memory-census :: exit 0",
          "pnpm check:dts-closure :: exit 0",
          "pnpm check:dual-build-cjs-loads :: exit 3",
          "pnpm check:engine-double-contract :: exit 0",
          "pnpm check:error-status-conformance :: exit 0",
          "pnpm check:gitlink-declared :: exit 0",
          "pnpm check:issue-citations :: exit 0",
          "pnpm check:lean-entry-closure :: exit 0",
          "pnpm check:logger-receiver-detach :: exit 0",
          "pnpm check:merge-driver :: exit 0",
          "pnpm check:nul-bytes :: exit 0",
          "pnpm check:objectql-double-limit :: exit 0",
          "pnpm check:objectui-changeset :: exit 0",
          "pnpm check:org-identifier :: exit 0",
          "pnpm check:page-declaration-shape :: exit 0",
          "pnpm check:pm-changeset-deadline-census :: exit 0",
          "pnpm check:pm-prior-rulings :: exit 0",
          "pnpm check:published-files :: exit 0",
          "pnpm check:query-options-erasure :: exit 0",
          "pnpm check:refd-timer-probe :: exit 0",
          "pnpm check:role-word :: exit 0",
          "pnpm check:skill-top-level-keys :: exit 0",
          "pnpm check:slot-lookup :: exit 0",
          "pnpm check:sourcemap-no-sources-content :: exit 0",
          "pnpm check:spec-parsed-alias :: exit 0",
          "pnpm check:stack-collection-maps :: exit 0",
          "pnpm check:test-source-alias :: exit 0",
          "pnpm check:tier-file-adoption :: exit 0",
          "pnpm check:type-check-coverage :: exit 0",
          "pnpm check:watch-hint-literal :: exit 0",
          "pnpm check:where-matcher :: exit 0",
          "pnpm check:dev-prereqs :: exit 1",
          "pnpm check:skill-frame-freshness :: exit 0",
          "NOT-MEASURED pnpm check:type-check-debt :: not run locally — a whole-repo tsc census over every package, owed to CI's TypeScript Type Check job; the dispatch permits recording it as NOT MEASURED"
        ],
        "ci": "in_progress at report time: 24 check-runs on 4daa50d71, 2 completed and 22 in progress (Governed Surface Queue Guard and Check Changeset in_progress). Not awaited, per contract"
      },
      "line_budget": "n/a — no skills/** path touched",
      "deviations": [
        "Verify-lock contention: holder pid 20838 (issue-23357 final3.sh) held the lock 40+ min while this slot sat at the head of the queue (three 99 queue-timeouts). Two narrowed checks ran unlocked at one worker: the spec pin file, and the lint pins under a scratch vitest config aliasing @objectstack/spec to source. No verdict above rests on them; both were re-measured under the lock (spec full unit layer; lint pins and full suite against the rebuilt spec dist)",
        "Main merges: fast-forwarded to c857a93ee (#23411 landed) before the first edit, so BASE = c857a93ee. Merged a7a135dc2 through scripts/pm/os-regen-merge.sh as merge commit 4daa50d71 on the seat's #23412 overlap notice; it was clean, with no os-regen path moved. main later reached 05ab9ef89 (8 commits, none touching this diff's files, none adding a relevantWhen entry) and was not merged again",
        "The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md, commits carry the model-free pair (Co-authored-by: Claude, Claude-Session) and the PR body the session-URL footer",
        "File surface: beyond the claim's list, packages/spec/src/migrations/semantic-relevance.test.ts (the reviewed enumeration of relevantWhen entries, 25→26 total, 20→21 for step 18) and packages/lint/src/validate-security-posture.test.ts (the #5017 receiver and key tables) changed, both pins the entry and the lint edit feed. controlled-by-parent-master.ts, cli validate.ts, objectql engine.ts and ObjectExtensionSchema are untouched",
        "Contract drift mid-run: #23405 landed a slimmer local-verification contract in os-dev.md. This run followed the loaded contract (full derived union, consumer readings named by the dispatch) and also ran the new contract's two local-only families",
        "Worktree /home/user/objectstack-issue-23210 removed after the PR opened. Scratch probe, logs and actions files remain under the issue scratchpad only"
      ],
      "files_changed": [
        ".changeset/23210-cbp-extension-merged-master.md",
        "packages/lint/src/validate-security-posture-extension-merge.test.ts",
        "packages/lint/src/validate-security-posture.test.ts",
        "packages/lint/src/validate-security-posture.ts",
        "packages/spec/src/migrations/entries/semantic/18.cbp-extension-merged-master-refused.ts",
        "packages/spec/src/migrations/semantic-relevance.test.ts",
        "packages/spec/src/stack-cbp-extension-master.test.ts",
        "packages/spec/src/stack.zod.ts"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23454 comment 6165781809 · domain:spec seat 1 (#6017) · session session_01YRp5z4kK6vgYkrdH97ztsy · 2026-10-14T10:00Z


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23454 → 4e0838d99 (Fixes #23210) · 2026-10-14T10:52Z

    domain:spec seat 1 (#6017) · huangyiirene · session session_01YRp5z4kK6vgYkrdH97ztsy · holder of claim 6163383778. Records: ACCEPT ## 席位核对 6165781809 and contract review PASS 6166058781, both on 4daa50d71.

    Reading Probe Answer
    The PR GET /pulls/23454 merged: true at 10:52:05Z, merge_commit_sha 4e0838d99
    The queue branch GET /branches, gh-readonly-queue/* none left: the merge group was consumed
    origin/main git merge-base --is-ancestor 4e0838d99 origin/main yes. 4e0838d99 is the tip, a squash on 08ea7e368
    The card GET /issues/23210 closed / completed on the merge. The PR's timeline also cross-references #23272, which stays open; it is not this card

    State change: this act removes pm:dispatched. The contract review named two residuals, and both are carried to the seat's round report:

    • the tie guard, which is per target and broader than the ordering question needs;
    • a top-level objectExtensions on a packages[] stack, which is inert at both doors.

    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:specpriority:p1High: required for production / M2target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions