Skip to content

Spec design: declarative membership keys for RLS (current_user.<key> from a lookup on records whose user field is the current user) #25234

Closed

Description

@objectstack-fleet

Ruled: 6355640929 · letter A · 2026-10-23T02:04:08Z

Filing gate ②: from the maintainer's ruling on objectstack-ai/cloud#3149 (batch #386 item 5, item 2). Filed by repo:cloud#1 (seat post #6026, session session_01FSg7JRUiTPo8GrgT38tAWP). ⛔ Not a claim. A spec design card: it adds protocol, so the design is put to the maintainer before any implementation starts (ruled A in 6355640929; implementation may be dispatched).

Reader who acts: the objectstack lane. objectstack-ai/cloud#3149 (the tracker) is Blocked-by: this card.

The gap (cloud#3149 item 2)

  • rls-membership-resolver (ADR-0105 D11) can express supplier in current_user.portal_supplier_ids, but only through code.
  • Installed package code does not run on hosted (docs/design/installed-package-handler-functions.md in cloud).
  • hotsrm (docs: core SRM design, industry packs, ADRs; governance templates and generator hotsrm#1) therefore uses one position per supplier, with RLS portal_position in current_user.positions. Every supplier-facing record must carry a stamped portal_position, and one missed stamp is an over-grant.

The ask

  • A declarative membership key in metadata, as the metadata twin of ADR-0105 D11: current_user.<key> = the values of lookup field F on records of object X whose user field U equals the current user.
  • The design round names: the declaration's home (object or app), the closed shape (X, F, U, an optional filter), how it is cached per request, how a cycle or an unbounded set is refused at publish, and how it shows in the security explainers.

Acceptance (for the design round)

A design comment the maintainer rules on, with the zod shape, the refusal list, one worked example (hotsrm's supplier contact), and the resolver path it reuses.

Activity

  1. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: claim 6343941655 (design round of domain:spec seat 2, session session_01B2EeooonSXrANpkpgUSfFZ) · released by domain:spec seat 1 (seat post #6017) · os-tesla · session session_013odhA26dvzy7pQmevdTTvy · 2026-10-23T15:11Z · reason: abandoned in flight with no takeover. The design round ended needs_decision, the ruling moved the card to pm:queue, and the assignee os-bill was left on it (a half state). Seat 2 is demoted to ⏳ vacant on #18549 (no own output since 2026-10-22T15:01Z). → pm:queue, assignee cleared; seat 1 dispatches next and re-claims.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_01M4rJHRAZDFqLYQ9dHMH339 (the card thread; seat session session_013odhA26dvzy7pQmevdTTvy posts this claim)
    Account: os-tesla
    Branch: claude/project-thread-3kk0c4
    Worktree: objectstack-issue-25234
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface: PR ① of ruling 6355640929 only — MembershipKeySchema + ObjectSchema.membershipKeys in packages/spec/src/**, the rls.zod.ts example fix, packages/spec/liveness/** (planned), the composeStacks duplicate-key refusal, generated references, tests, the changeset (stop on breach; explain in the report). ⛔ no skills/** edit in this PR (the Tier H row is reported as text and lands separately), no plugin-security / lint / ADR edit.
    Container & model: L, mode:thread, model: default tier (dispatch-gates --tier: "no path-derived mandate", floor sonnet · default opus · ceiling fable), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: n/a — not a defect card
    Thread-read: none
    Serial constraints cleared: seat 2's design-round claim 6343941655 released by this seat after seat 2's demotion on #18549. #25233 stage 1 is dispatched in parallel on non-spec files; PR ② (plugin-security) is serialised against #25233's stage 2 by the seat.

    The platform lets the card thread push only its designated thread branch, so Branch: records that branch, not claude/issue-25234-<slug>. Dispatch order: the project's shared folder, spec-seat-1/dispatch-25234.md. The seat runs a CONTRACT_REVIEW_TIER review before the queue.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25234,
      "status": "done",
      "branch": "claude/project-thread-3kk0c4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25513",
      "session": "session_01M4rJHRAZDFqLYQ9dHMH339",
      "premise_still_valid": true,
      "summary": "PR 1 of ruling A (6355640929), the spec half, as a draft that leaves the card open (Part of). ObjectSchema.membershipKeys on the roster object: MembershipKeySchema (userField, valueField, filter, label, description; strict, valueField equal to userField refused), the map refusing a non-snake_case name and every RESERVED_RLS_MEMBERSHIP_KEYS name with a per-key message, MEMBERSHIP_KEY_MAX_VALUES = 1000 as a constant, ObjectExtensionSchema guidance; defineStack and composeStacks refuse one key on two objects (STACK_CROSS_REFERENCE_INVALID / 422); liveness planned with 5 children and one author warning (probed: 1 finding, control 0); the rls.zod.ts examples no longer say the runtime stages territory_account_ids / team_member_ids; form ledger omit row; generated artefacts; changeset minor spec + patch metadata-core. Deviation from the design's sketch, declared in the PR: the schema lives in security/rls.zod.ts beside DefaultRowScopeSchema (the precedent's home), because a new security/ module made gen:skill-refs rewrite two skills/ index files the claim excludes; label/description are z.string() not I18nLabelSchema. Surface beyond packages/spec/src declared: metadata-core FLS classification + pin and the metadata-protocol /meta/types count test (both red otherwise, the #24398 precedent), and docs/audits strictness counts (generated). The Tier H skills row is in tier_h_skills_row, not in the diff.",
      "tests": "head b2b98c41 via os-verify-lock: spec test 713 files / 21684 passed / 1 todo (VERDICT command-exit 0) + spec typecheck exit 0; metadata-core 19 files / 796 passed + typecheck 0; metadata-protocol meta-types test 18 passed; lint 4 files / 694 passed; objectql 4 files / 160 passed (closure rebuilt from head). New suite object-membership-keys.test.ts 25 tests. Ablation (one): one-stack door push replaced via ablation-replace.mjs, blob 208905c1ae7c to 98fa82b5718f, red as expected (1 failed / 24 passed), restored blob == HEAD, git diff HEAD empty; no build (relative src import). Reverse .d.ts probe in platform-objects: key accepted exit 0, valueField: 5 TS2322 exit 2; inner unknown member typechecks (noted).",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on head b2b98c41: 116 derived, 116 run sequentially, 116 exit 0 (exit captured before any pipe); --ran reconciliation 116/116, 0 NOT-MEASURED. First pass on b595703e: check:spec-parsed-alias exit 1 (fixed in b2b98c41), 11 exit 3 PREREQUISITE NOT MET (stale dist / lint dist absent), all 0 after rebuild; check-plugin-teardown-shape --self-test needed pinned 621a4876 fetched --depth=1. check:dev-prereqs (local-only) exit 0. CI families: the PR's check-runs, in_progress at report time.",
      "line_budget": "26 files, +872 / -37 (909 changed lines), under the 3000 human-merge threshold; precedent #24398 +549/-83",
      "files_changed": [
        "packages/spec/src/security/rls.zod.ts",
        "packages/spec/src/data/object.zod.ts",
        "packages/spec/src/stack.zod.ts",
        "packages/spec/src/data/object-membership-keys.test.ts",
        "packages/spec/src/compose-stacks-merge-collection-refusal.test.ts",
        "packages/spec/src/compose-stacks-collection-pipe-arm.test.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/liveness/object.json",
        "packages/spec/liveness/state-counts/object.md",
        "packages/spec/dropped-refinements.baseline.json",
        "packages/spec/{api-surface,authorable-surface,declaration-map,export-origins,json-schema.manifest} (generated)",
        "content/docs/references/** (generated, 5 pages)",
        "docs/audits/2026-07-unknown-key-strictness-ledger.counts/security.md (generated)",
        "packages/metadata-core/src/object-schema-fls-references.ts",
        "packages/metadata-core/src/object-schema-fls-references.test.ts",
        "packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts",
        ".changeset/25234-object-membership-keys.md"
      ],
      "deviations": [
        "schema home security/rls.zod.ts, not a new membership-key.zod.ts (precedent home; a new module rewrote skills/ reference indexes via gen:skill-refs)",
        "label/description typed z.string() (design sketch said I18nLabelSchema)",
        "file surface beyond packages/spec: metadata-core FLS classification + test, metadata-protocol count test, docs/audits generated counts — each red or stale otherwise, as on #24398"
      ],
      "tier_h_skills_row": {
        "file": "skills/objectstack-data/rules/security.md",
        "insert_after": "the `current_user.positions` row of the placeholder table (line 112 at ab510f42e7)",
        "text": "| `current_user.KEY` (a declared membership key) | the values of `valueField` on the rows of the roster object that declares `membershipKeys.KEY` whose `userField` is the caller (for `IN`; planned: no server stages it yet, so a policy reading it matches no rows) |",
        "line_delta": "+1 line, no deletion"
      },
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — GitHub reads went through unauthenticated REST (curl) for #25234, its comments and PR #24398; no MCP GitHub tool called",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls via fleet-write relay (PR #25513, read-back byte-identical, assignee os-tesla); POST /repos/objectstack-ai/objectstack/issues/25234/comments via post-stamped (this report)",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #25234 PR 2 · @objectstack/objectql SchemaRegistry.registerObject refuses `defaultRowScope` on an `extend` contribution (EXTENSION_DEFAULT_ROW_SCOPE_REFUSED_CODE) but has no refusal for `membershipKeys`; whether the extension merge carries the key onto the owner's object is NOT MEASURED; no effect until the reader lands · noted, not filed"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing plan for the remaining PRs · domain:spec seat 1 · 2026-10-23T17:19Z

    Ruling 6355640929 orders PR ① → ② → ③, with ④ (the ADR-0105 D11 note) in parallel. PR ① is PR #25513 (Part of #25234, contract review PASS). Carried forward from that review:

    • Closing PR: PR ③ (lint refusals and runtime-gate registration) carries Closes #25234. PRs ① and ② say Part of #25234.
    • PR ② must also close the objectql registry extend door. SchemaRegistry.registerObject refuses defaultRowScope on an ownership: 'extend' contribution by name, but has no membershipKeys analogue, and mergeObjectDefinitions drops the key silently (ADR-0078). Add a by-name refusal beside the defaultRowScope one, or a merge that carries the key, before stageRlsMembership reads it.
    • PR ② is serialised against Security: an external organisation role whose members do not see the member directory and reach data only through explicit grants (portal users on hosted environments) #25233's stage 2 (both touch plugin-security; whoever lands second merges main).
    • Tier H skills/objectstack-data/rules/security.md row: the text is in os-dev-report 6370454361 (tier_h_skills_row). It lands as its own governed PR together with, or re-worded by, PR ② when liveness flips to live, and the maintainer merges it.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat ACCEPT on PR #25513 (PR ① of 3): comment 6371079096 · 2026-10-23T17:44Z. Queue landing enabled; card stays pm:dispatched for PR ② and ③.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25234,
      "status": "done",
      "branch": "claude/project-thread-3kk0c4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25528",
      "head": "5f35aff38a34a4aa5b170d2803e12ce43b3d0dcd",
      "session": "session_01M4rJHRAZDFqLYQ9dHMH339",
      "premise_still_valid": true,
      "summary": "PR 2 of ruling A (6355640929; landing plan 6370632236), the reader, as a draft with Part of #25234. plugin-security stageRlsMembership now stages ObjectSchema.membershipKeys beside the registered rls-membership-resolver: lazily, only keys a policy about to compile reads (current_user.* names parsed once per predicate via parseCelToAst after sqlPredicateToCel, cached), on the read door and the write check alike, memoised per key per request. The read is X where U == userId AND the compiled filter AND the caller's own Layer 0 filter for X (isPlatformAdmin false), projected to id + F, limit 1001, under { isSystem: true } with no tenantId so the where wall is the only org scope. Fail closed: no row stages []; over 1000 rows/values, read failure, filter refused by RLSCompiler, tenant wall deny, no user leave the key unresolved with a warn; a key declared on two objects, or one the resolver also owns (its keys or staged this request), is unresolved and logged as an error (resolver collision also at boot naming both owners), and the resolver's value is withdrawn. Explain: the object-level rls detail names each key read (label, description, X, F, U, filter, resolved size or miss reason) and the permission sets whose holders can insert/update X; a record-grained business_rls rule reads via membership:KEY and names the linking roster row. objectql: SchemaRegistry.registerObject refuses an extend contribution carrying membershipKeys (INVALID_METADATA / 422, ExtensionMembershipKeysRefusedError) beside the defaultRowScope refusal; measured first that mergeObjectDefinitions dropped it silently. Liveness membershipKeys + 5 children planned to live (authorWarn/authorHint dropped); spec wording no longer says not applied. Serial with #25233: PR #25515 landed first (9019af9f), so this head merges main 74496c64 cleanly (5f35aff3). The PR body's line naming the earlier merge of aa2dbab7 is stale on that point; the relay has no PR-edit op, so it is recorded here.",
      "riders": {
        "1_layer0_system_read": "pinned: the portal set has no grant on the roster and its own find is PERMISSION_DENIED while its PO read resolves the key; unit test asserts byte-identical find args (where with org term, fields, limit, context { isSystem: true }) for MEMBER, external audience, platform admin, tenant admin",
        "2_audience_neutral": "pinned: MEMBER, audience external and TENANT_ADMIN resolve the same rows",
        "3_explain_names_x_and_writers": "pinned: object-level detail names X and the holders of insert/update on X via the security catalog's permission sets and PermissionEvaluator.checkObjectPermission; record-level via membership:KEY",
        "4_serial_with_25233": "#25515 merged 2026-10-23T19:34Z; main merged here after it, re-verified, CI green"
      },
      "tests": "post-merge head 5f35aff3 via os-verify-lock (slot issue-25234): plugin-security closure build (dts) exit 0; plugin-security typecheck exit 0; plugin-security 220 files / 4607 passed / 45 skipped exit 0; objectql 466 files / 8700 passed exit 0. Pre-merge on e35ae5da: spec 792 files / 22953 passed / 1 todo; objectql tsc exit 0. New suites: object-membership-keys.test.ts 21 (real SecurityPlugin + ObjectQL + SqlDriver, isolated posture), registry-extension-membership-keys-refused.test.ts 6. Ablations, each restored byte-identically: declared staging removed 12 red / 9 green; write-side call reverted 1 red (insert check); roster read under caller context instead of isSystem 11 red incl. both rider-1 pins; Layer 0 term dropped 8 red; objectql refusal disabled 4 red / 2 controls green.",
      "gates": "dispatch-gates --commands: 124 derived, 124 run sequentially, exit captured before any pipe; --ran reconciliation on e35ae5da 124/124, 0 NOT-MEASURED, all exit 0. Real findings fixed: check:doc-authoring (tracker id in 3 runtime log strings, e35ae5da) and, caught by CI, check:optional-error-sink (MembershipKeyStagingHost.logger had both warn and error optional; warn now required, 3c309af1, OES exit 0 locally). Environment-only first-pass codes: check-engine-split-ratio exit 2 on shallow clone (fixed by fetch --shallow-since), check:skill-examples / check:dual-build-cjs-loads / check:i18n exit 3 until a full workspace build. CI on 5f35aff3: 42 check runs, 36 success, 6 skipped, 0 failed.",
      "line_budget": "17 files, +1493 / -79 (1572 changed lines), under the 3000 human-merge threshold; of which tests 591 lines (2 new suites)",
      "files_changed": [
        "packages/plugins/plugin-security/src/object-membership-keys.ts (new)",
        "packages/plugins/plugin-security/src/object-membership-keys.test.ts (new)",
        "packages/plugins/plugin-security/src/security-plugin-rls-filter.ts",
        "packages/plugins/plugin-security/src/security-plugin.ts",
        "packages/plugins/plugin-security/src/tenant-layer.ts",
        "packages/plugins/plugin-security/src/explain-engine.ts",
        "packages/objectql/src/registry.ts",
        "packages/objectql/src/registry-extension-membership-keys-refused.test.ts (new)",
        "packages/spec/liveness/object.json",
        "packages/spec/liveness/state-counts/object.md (generated)",
        "packages/spec/src/data/object.zod.ts",
        "packages/spec/src/security/rls.zod.ts",
        "content/docs/references/** (generated, 4 pages)",
        ".changeset/25234-membership-keys-staged.md"
      ],
      "deviations": [
        "tenantLayer0InputOf extracted in tenant-layer.ts so the read door and the roster read build the Layer 0 input from one literal (computeLayeredRlsFilter now calls it; behaviour unchanged, suites green)",
        "the roster system context carries no tenantId: with one, the engine scoped the driver to the active org on its own, which would narrow a group-posture key below the wall; the where wall is the only org scope (Layer 0 ablation 8 red)"
      ],
      "tier_h_skills_row": {
        "file": "skills/objectstack-data/rules/security.md",
        "replaces": "the planned row from report 6370454361",
        "text": "| `current_user.KEY` (a declared membership key) | the values of `valueField` on the rows of the roster object that declares `membershipKeys.KEY` whose `userField` is the caller and on which its `filter` holds, inside the caller's organization (for `IN`; read once per request even when the caller cannot read the roster; more than 1,000 values, a failed read, or a key a registered resolver also owns matches no rows) |",
        "line_delta": "1 line replaced, no addition"
      },
      "dogfood_battery": "n/a: no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "read-only GitHub MCP calls (check runs, job logs) for CI triage; no MCP write",
      "api_writes": "2: POST pulls via fleet-write relay (PR #25528, read-back identical); POST issues/25234/comments via post-stamped (this report). Pushes to claude/project-thread-3kk0c4 only: a718adcc, 21cace53, e35ae5da, 3c309af1, 5f35aff3",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat ACCEPT on PR #25528 (PR ② of 3): comment 6375208026 · 2026-10-23T21:36Z. Queue landing enabled; card stays pm:dispatched for PR ③.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25234,
      "status": "done",
      "branch": "claude/project-thread-3kk0c4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25550",
      "head": "cf991db317782291a2a5be83eafd822638b766cc",
      "session": "session_01M4rJHRAZDFqLYQ9dHMH339",
      "premise_still_valid": true,
      "summary": "PR 3 of 3 of ruling A (6355640929; design 6344270438; landing plan 6370632236), the authoring refusals, as a draft with Closes #25234, on main after #25528 (e5eab065). New gating rule validateMembershipKeyDeclarations (CLI_AND_RUNTIME, runtimeTypes object): membership-key-user-field-invalid (refusal 5: U a single-valued user reference on the merged object), membership-key-value-field-invalid (6: F a lookup/master_detail/user), membership-key-declared-twice (3: at the save door reading the live objects the stack does not carry, outside the package closure), membership-key-resolver-collision (4: save door only). validateRlsPredicateEnforceability learns keys and now runs for object writes too (runtimeTypes permission, object): a key filter is judged as an RLS clause at objects[N].membershipKeys.KEY.filter with the roster as target, plus a caller-read check (7); new rls-predicate-membership-key-target for a declared key tested against a column of another target (11); a declared key under == is the existing list type fault (13); at the save door only, x in current_user.KEY that no kernel key, declaration or registered resolver owns is rls-predicate-unknown-user-variable (12). Host fact: protocol.ts rlsMembershipResolverKeys reads RLS_MEMBERSHIP_RESOLVER_SERVICE keys per publish ([] when none; undefined, so not judged, with no registry or unreadable keys) and the gate builds membershipKeyOwners from the un-narrowed context.objects, the written stack authoritative for the objects it carries. os explain entries for the five new ids and three new unknown-user-variable paragraphs.",
      "tests": "lint 158 files / 7237 passed, tsc exit 0, dts build 6/6; metadata-protocol 261 files / 21457 passed / 19 skipped plus 4 new host cases, tsc exit 0; cli rls-policy-authoring-admission 40 passed. New suites: validate-membership-key-declarations.test.ts 17, validate-rls-predicate-enforceability.membership-keys.test.ts 24, protocol.runtime-authoring-gate.test.ts +4. Ablations, each restored byte-identically: refusal 12 arm 3 red; 11 arm 7 red; 13 swap 2 red; 7 caller check 1 red; 7 judge pass 6 red; stack authority 1 red; the six findings.push sites of the declarations rule 1/6/2/1/4/3 red; host resolver read replaced by undefined 2 red / 2 green.",
      "gates": "dispatch-gates --commands on d1ddcd9f: 71 derived, all run sequentially under os-verify-lock (slot issue-25234) after a dts build of the cli closure, plus 58 more from the long listing; all exit 0 except one real finding, fixed in d16c4a71 (check:docs-transcript-drift: four docs transcripts said 51 author-time rules, the validate registry now derives 52), and four PR-context guards NOT WIRED locally (closing-target-claim, partof-closing-keyword, single-claim-paths, governed-queue-guard), all green on CI; partof also run locally with the PR body as PR_BODY, pass. CI on cf991db3: 42 check runs, 0 failed.",
      "line_budget": "20 files, +1868 / -122 (1990 changed lines), under the 3000 human-merge threshold; tests 731 lines",
      "files_changed": [
        "packages/lint/src/validate-membership-key-declarations.ts (new)",
        "packages/lint/src/validate-membership-key-declarations.test.ts (new)",
        "packages/lint/src/validate-rls-predicate-enforceability.ts",
        "packages/lint/src/validate-rls-predicate-enforceability.membership-keys.test.ts (new)",
        "packages/lint/src/authoring-rules.ts",
        "packages/lint/src/runtime-gate.ts",
        "packages/lint/src/index.ts",
        "packages/lint/src/rule-explanations.ts",
        "packages/lint/src/runtime-gate.object-writes.test.ts",
        "packages/lint/src/validate-rls-predicate-enforceability.engine-judge.test.ts",
        "packages/lint/src/validate-rls-predicate-enforceability.test.ts",
        "packages/metadata-protocol/src/protocol.ts",
        "packages/metadata-protocol/src/runtime-authoring-gate.ts",
        "packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts",
        "packages/cli/test/rls-policy-authoring-admission.test.ts",
        "content/docs/deployment/validating-metadata.mdx",
        "content/docs/deployment/cli.mdx",
        "content/docs/getting-started/build-with-claude-code.mdx",
        "content/docs/ui/react-pages.mdx",
        ".changeset/25234-membership-key-authoring-refusals.md"
      ],
      "deviations": [
        "refusal 3 also runs at the save door (the design table names the runtime gate against the registry); defineStack already refused it within one stack",
        "registering the RLS rule for object writes also judges defaultRowScope at the object door and refuses an object write that drops a field or key a stored policy reads (differential: an already-failing stored policy is not blamed); stated in the changeset BREAKING section",
        "the cli real-engine admission test's app-staged current_user.holidays cases now register a resolver owning holidays; a new case pins refusal 12 end to end (CLI accepts, save door 422)",
        "validating-metadata.mdx door table: the RLS rule gets its own row (permission, object at the save door; the old shared row said not at the door, stale since the permission crossing) and the declarations rule a row"
      ],
      "dogfood_battery": "cf991db3 · os-verify-lock VERDICT command-exit 0 · Test Files 291 passed / 3 skipped (294) · Tests 2500 passed / 18 skipped (2518) · no failures",
      "mcp_calls": "read-only GitHub MCP calls (check runs, job logs) for CI triage; no MCP write",
      "api_writes": "2: POST pulls via fleet-write relay (PR #25550, read-back identical); POST issues/25234/comments via post-stamped (this report). Pushes to claude/project-thread-3kk0c4 only: d16c4a71 (with d1ddcd9f), cf991db3",
      "open_questions": [],
      "out_of_scope_findings": [],
      "next": "after this lands, the Tier H skills/objectstack-data/rules/security.md row as its own draft PR, text per report 6374979058"
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat ACCEPT on PR #25550 (PR ③ of 3): comment 6377103312, contract review 6377122276 (PASS) · 2026-10-23T23:56Z. Queue landing enabled; on merge this card closes and the Tier H skills row follows as its own governed PR.


    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 guardsdomain:specenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions