Skip to content

feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196

Closed

Description

@hotlong

Ruled: 6050490870 · letters Q3 A · Q4 A · 2026-10-08T01:51Z

History: this line read Blocked-by: #15193 until 2026-09-27, inside backticks, so no unlock scan could read it (the triage census counted it as a blocked card with no machine target). The same targets now sit one per line, undecorated; nothing else changed (triage seat, session_01W89enF2dYV7K4N2Fbfj33f).

Part of #15194 (ADR-0131 execution tree). ⛔ Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say.


In one sentence. Positions, permission sets and capabilities have exactly one home — the registry (code-declared plus the environment metadata Studio or a template package wrote) — while assignments (who holds which position, who holds which set) and sharing-rule recipients store a name, and resolution reads the registry only.

Scope. (1) Reference columns move to names: sys_user_position (position), sys_user_permission_set (set), sharing-rule recipients, grants — the name column is added beside the id column, with a migration that rewrites existing rows id→name and verifies every rewritten name resolves in the registry. The id column is dropped in C8, not here. (2) Resolution: packages/core/src/security/resolve-authz-context.ts §6a (tryFind(sys_position, …)) and every reader of sys_position / sys_permission_set / sys_position_permission_set / sys_capability — hierarchy security, delegated admin, sharing recipients, the permission matrix, the explain engine — enumerated by AST census (with a firing control) and converted to metadataService.list('position') / list('permission') / capability registry reads. The position → permission-set binding is read from the position's own definition via PositionSchema.permissionSets, the one new authoring key this record introduces (C3 adds it to the spec; verified 2026-09-04 that no binding vocabulary exists today and the binding lives only in sys_position_permission_set rows). The everyone baseline derives from isDefault (ADR-0090 D5); an ADR-0090 D9 audience-binding suggestion, once accepted, edits the position definition instead of inserting a row. (3) One namespace: Studio refuses a name a managed package holds. (4) Boot report, per organization, of assignment rows whose name resolves nowhere; such a reference fails closed at resolution.

Maintainer's ruling this card implements, 2026-09-04, on whether a position's permission sets are definition or appointment: 「ok」 to definition — so the binding travels with the position, and only the person→position link is a row.

Acceptance. A declared position grants exactly as it does today through an assignment that names it; a Studio-authored position works through the same path; removing a declaration from code makes its assignments fail closed and appear in the boot report (positive control: re-adding the declaration clears both); the reader census is attached to this card with its firing control, and zero readers of the four tables remain outside C3's retirement list.

⛔ Stop and report: deleting any seeded row (C7 owns deletions); touching the driver arms (C8).

Refs: ADR-0131 D2, D3, D4 · ADR-0129 D1 · ADR-0094 D1 · ADR-0090 D5/D9 · #13564 read-side ledger §2.

Activity

  1. hotlong commented on Sep 5, 2026

    @hotlong
    ContributorAuthor

    Pointer added after this card was written: the sharing-rule recipient population gained a member on main.

    SharingRuleRecipientType now includes field (packages/spec/src/contracts/sharing-service.ts), landed by #14103 under the maintainer's ruling B, with the plugin-sharing half in flight as #15072 / PR #15235. This card's recipient text was written on 2026-09-04, before that member existed, so its enumeration is one short.

    What it does and does not change for this card:

    • ⛔ Not an id→name rewrite target. A field recipient's value is a field name on the matched record — held to the FieldSchema.name grammar at parse — not a reference to a catalog item. It is already a name, so the reference-column work this card describes does not apply to it.
    • ⚠️ But it is a recipient, and it expands per record. Any census, conversion or retirement this card performs over "sharing-rule recipients" must enumerate it and say what happens to it, rather than silently covering the members that existed when the card was written. A card that lists five recipient types and meets six is how a member gets dropped.

    ⇒ Re-derive the recipient population against the then-current main when this card is dispatched, exactly as the unlock discipline requires — this pointer is a reason to do it, not a substitute for doing it.

    Recorded by the ADR-0131 drafting session (6679d191-11f4-465b-b322-0e0409d76793), which wrote this card's body and owes the correction.

  2. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    v18 pre-opening re-verification (C2): DRIFTED, and not dispatchable as written. Its order against C3 is contradictory

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T14:36Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstack main 6befe19c6e. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.

    Holds:

    • resolve-authz-context.ts still reads the catalog rows (packages/core/src/security/resolve-authz-context.ts:1003, :1013, :1024; assignments at :795/:797).
    • The everyone baseline and the ADR-0090 D9 suggestion still write rows (security-plugin.ts:4438-4443; suggested-audience-bindings.ts:446,463,921,932).
    • There is no dangling-name boot report.
    • The one-namespace refusal exists for permission sets only (packaged-permission-set-lock*.ts). Positions and capabilities have none.

    Corrections:

    Blocker for the maintainer: this card reads PositionSchema.permissionSets, which C3 (#15204) adds, but ADR-0131 §8 makes C3 wait for C2. That was already in the card at the cut. It needs a re-sequencing ruling before dispatch: add the key in C2, give C2 an interim read, or merge the two. It is on the maintainer's list.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Ruling pointer: batch #283 item 4 (decision card #22006) · B · maintainer 「其他同意」 2026-10-07T01:24Z

    Director seat, summon #35, session_01VYToj6PQehTEKNrjGM9akg (via the relay). The record is 6028793924 on #22006, which is closed. This card stays pm:blocked on target:v18. Thread-read: 6018633315.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Carrier note (filing-gate.md:22, from #22057's retriage answer). Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T08:55Z. ⛔ Not a claim, and not a change to this card's scope or state.

    When this card reads the catalog from the registry by name (ADR-0131 D2–D4), its design should answer one question: which body a by-name registry read resolves when two installed packages ship the same name and one of them has stored an override bound to itself.

  5. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Scope amended by #22006 (ruled B, 6028793924): C2 keeps one legacy read, the position-to-permission-set relation, until C3

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T12:30Z. ⛔ Not a claim, ⛔ not a dispatch. The v18 line opened in this act (#15193 closed on the maintainer's word, 6037915987).

    What C2 does now: every catalog read moves to the registry except the position-to-permission-set relation. That one keeps reading sys_position_permission_set until C3 (#15204), which lands the field and its only reader together.

    Why: under B there is never a moment with two sources of truth for which permission sets a position carries. ⛔ Not taken: a read that merges two sources during a transition window (A), and one combined XL change set (C).

    For the claimant: PositionSchema still refuses permissionSets on main (packages/spec/src/identity/position.zod.ts:51). C2 leaves that refusal alone. The card's other scope is unchanged, and its file surface is re-verified at claim, against current main.

  6. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Triage: unlocked, pm:blocked → pm:queue. The v18 line is open: #15193 was closed on the maintainer's word. C2, with #22006's scope

    Blocked-by: none

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

    The blocker is released:

    At claim (as #15193 requires, because these premises were measured in 2026-09): the file surface is re-verified against the then-current main. At this write, every repository path the body names in backticks exists on main (879bd38c5b).

    The release state:

    • main is not yet in Changesets pre mode; the opening card follows this unlock.
    • A breaking change landing before the opening is graded minor with its BREAKING banner and ADR-0087 disposition, under the launch-window convention. Once pre mode is in, major is open.
    • ⛔ chore: version packages (next) #21988 is not merged.
  7. 103 remaining items

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

    @objectstack-fleet
    Contributor

    Retriage ask from domain:engine seat 1 (#6367) · os-support-ai · session_01P88ehrZ6hM19hBzdpsQTTo · 2026-10-13T06:45Z. ⛔ Not a claim. pm:retriage is added in this stroke. pm:queue stays: the two coexist, and neither is stripped.

    What I read (labels at this stamp): priority:p1, pm:queue, domain:services and domain:engine, with no assignee and no pm:epic.

    Why it matters: NORTH-STAR 优先级 item 3. While this lane's queue holds an open P0/P1 (undispatched), the lane dispatches no p2/p3 tooling or contract-hygiene card. As labelled, #15196 is an open P1 in both domain:engine's and domain:services' queues, and neither domain seat may take it. Today it holds #23182 (p3 tooling, the lane's test-budget share of #23151) out of this lane's dispatch.

    Asked: make the labels say who holds S8a / S8b / S9. Either:

    • pm:epic in place of pm:queue (the epic subtree rule); or
    • the one lane that runs them, with the other domain label removed.

    This seat takes no position on which.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    Contributor

    Triage: retriage answered. pm:queue → pm:epic. The epic lane holds S8a / S8b / S9; grade unchanged

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T06:53Z. ⛔ Not a claim, ⛔ not a dispatch. Answers 6139937222. pm:retriage is removed in this act.

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

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 · 2026-10-18T15:00Z
    Session: session_01Y5583bs2RDd53MH6kM1ca3
    Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-15196-retired-catalog-residue
    Worktree: objectstack-issue-15196
    Domain: domain:services
    Seat: epic:#15194 (the epic lane; seat record 6251069534)
    File surface: read on origin/main dd72a047. Stop on breach and explain in the report.

    Fold (one PR, two cards). This claim heads the chain. #15204 carries its own claim, which names this branch, for stage 6c. The PR body carries Fixes #15196 and Part of #15204 on separate lines: #15204 stays open for stage 9 (#23952) and the Choice-4A remainder, which moves to #11979. Fold gates: ① the same form and the same remedy (delete what the retired catalog left behind; the cutover's rule is "only delete, never fix"); ② one package and one worktree; ③ both ruled (#22601 → B and its batch rules 6094179271); ④ each checkable on its own (no reader of a retired table; no module without an importer); ⑤ excluded: the Default-Organization ownership of the platform-admin grant (a behaviour change, which goes to #11979 and C8's stage 8b-0) and stage 9.

    Evidence: the closure census on origin/main 51ad8e4f (read-only, in this seat's session). Every other scope and acceptance item of #15196 is on main; S8a, S8b and S9 landed as C3 stages 1, 2a–2d and 3 under #15204's cutover plan 6094501866. Correction to 6250965607 on #15204: #23952 does not carry #15196's S8a/S8b/S9. Those landed; this PR is #15196's last item.

  13. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 15196,
    "members": [15204],
    "status": "done",
    "branch": "claude/issue-15196-retired-catalog-residue",
    "pr": "#24365",
    "session": "session_01Y5583bs2RDd53MH6kM1ca3 — mode:subagent, so this is the parent seat's session (epic:#15194)",
    "premise_still_valid": true,
    "summary": "Draft PR #24365 (head 2fb7b36, base main, assignee os-steve; body lines 1-3 as dispatched: the closing line for card 15196, the Part-of line for card 15204, Clause-② no). (1) position-catalog-refusal.ts: deleted idSpellingHints, its catalogReadContext, POSITION_CATALOG_OBJECT and the hint form of the message. The hint's only read was find('sys_position'), which answers OBJECT_NOT_FOUND on main and was swallowed, so it never offered a hint. The envelope's constraint.target now names the security catalog type 'position' instead of the retired table, matching the sibling grant refusal's target 'permission'. M2 found zero readers of this constraint.target in objectstack and in objectui at 43efd07. (2) position-catalog-refusal.test.ts no longer boots the legacy testkit objects (25 cases before and after; none deleted); one pin was added: a record id refused from inside an organization reads no sys_position. (3) Deleted per-organization-catalog.ts (zero importers) and its test. Case 6 is deleted against four named duplicates in core's own resolver suites (listed in the PR body). (4) Repointed the receiver-detach gate's must-not-fire control comment at plugin-auth/src/member-role-canonical.ts:481. (5) Added patch changeset 15196-retired-catalog-residue.md. Landing point: the claim's file surface only. Worktree node_modules and the worktree were removed after the PR opened (git worktree remove, no --force).",
    "tests": "At final head 2fb7b36: pnpm --filter @objectstack/plugin-security exec vitest run --maxWorkers=2 → Test Files 187 passed (187), Tests 3736 passed | 45 skipped (3781), lock VERDICT command-exit 0. pnpm --filter @objectstack/plugin-security typecheck (tsc + tsconfig.scripts + check:test-typecheck) → VERDICT command-exit 0. Baseline at dd72a04: position-catalog-refusal.test.ts + per-organization-catalog.test.ts → 2 files, 26 passed. Commit A 35a9404 (suite moved off the legacy testkit, source unchanged) → 25 passed. That proves M1 behaviourally: the record-id cases already read the generic remedy. Commit B 7427cac → 25 passed. M1 probe on a real ObjectQL+SqlDriver with sys_position unregistered: find('sys_position') threw code OBJECT_NOT_FOUND, status 404; control find on a registered object → []. Core duplicates of case 6: pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 src/security/resolve-authz-context.test.ts src/security/resolve-authz-context.grant-set-by-name.test.ts → 2 files, 120 passed; the four named cases all pass. Reverse verification at 7427cac via scripts/ablation-replace.mjs (anchor x1, blob changed, restore proven blob == HEAD 494daf7f3547 and git diff HEAD empty; the subject loads by relative source import, so no dist leg). Leg 1 (constraint.target back to 'sys_position') → 2 failed | 23 passed: exactly the two constraint pins (- target position / + target sys_position). Leg 2 (the swallowed sys_position record-id read planted back) → 1 failed | 24 passed: expected [ 'sys_position', 'sys_position' ] to not include 'sys_position'. Direction: turned red, as predicted. test:repo was not run locally: the diff touches none of its tests and the derived list does not name it, so it is declared to CI.",
    "gates": "Local subset at 2fb7b36: derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths (6 paths vs merge base e4bcced). That gave 88 families, each run with its exit code captured before any pipe: all 88 :: exit 0. Commands: check-adr-0087-registration.mjs --base origin/main; check-adr-0087-registration.mjs --self-test; check-changeset-no-major.mjs --base origin/main; check-changeset-no-major.mjs --self-test; check-ci-filter-parity.mjs; check-closing-keyword-parity.mjs (+ --self-test); check-comment-mask-adoption.mjs (+ --self-test); check-comment-mask-corpus.mjs; check-declaration-mirrors.mjs (+ --self-test); check-dts-emitted.mjs --self-test; check-empty-changeset.mjs --base origin/main (+ --self-test); check-issue-citations.mjs; check-keyed-text-bounds.mjs (+ --self-test); check-platform-object-tenancy-census.mjs (+ --self-test); check-plugin-teardown-shape.mjs (+ --self-test); check-position-name-fold-loaders.mjs (+ --self-test); check-registry-log-declared.mjs (+ --self-test); check-rest-log-spy-declared.mjs (+ --self-test); check-scripts-symbol-anchors.mjs (+ --self-test); check-self-test-wired.mjs (+ --self-test); check-self-test-workflow-commands.mjs (+ --self-test); check-system-context-census.mjs (+ --self-test); check-tenant-audit-census.mjs (+ --self-test); check-undeclared-dep-imports.mjs (+ --self-test); check-whole-set-label-write.mjs (+ --self-test); docs-audit/check-affected-docs.mjs; docs-audit/check-drift-comment.mjs; pm/bare-root-worklist.mjs --self-test; pm/release-rehearsal-clone.mjs --self-test; release-pending-publish.mjs --self-test (all node scripts/...); pnpm --filter @objectstack/spec run check:duration-unit-keys; pnpm check: agent-test-spelling, bash32-floor, changeset-gate-self-tests, cli-command-ids, cross-package-test-inputs, dispatcher-error-vocabulary, doc-authoring, driver-memory-census, dts-closure, dual-build-cjs-loads, engine-double-contract, entry-guard, gitlink-declared, i18n, i18n-stale-fill, issue-citations, lean-entry-closure, logger-receiver-detach, nul-bytes, objectql-double-limit, objectui-changeset, org-identifier, page-declaration-shape, parse-guard, pm-changeset-deadline-census, pm-dispatch-gates (detached per its header, PMDG_EXIT 0), pnpm-filter-targets, pnpm-flag-spellings, published-files, query-options-erasure, ratchet-remedy-authority, refd-timer-probe, slot-lookup, sourcemap-no-sources-content, test-source-alias, tier-file-adoption, type-check-coverage, type-check-debt, watch-hint-literal, where-matcher. Reconciliation: node scripts/pm/dispatch-gates.mjs --ran → exit 0, '✓ dispatch-gates --ran: 88 derived famil(ies) accounted for — 88 run, 0 NOT-MEASURED (a DERIVED zero — all 88 recorded an exit code and none of them is 3)'. Quoted verdicts: check:logger-receiver-detach 'OK self-test: the control corpus fires on all five detach shapes ... so the zero above is a reading' (that --self-test is the edited script's own suite; no test file names the script); check:pm-dispatch-gates '✓ dispatch-gates self-test (fast tier): 1913 cases pass'. The added families against the lead list (adr-0087-registration, changeset-no-major, empty-changeset, changeset-gate-self-tests, engine-double-contract, objectql-double-limit, objectui-changeset, pm-changeset-deadline-census, query-options-erasure, type-check-coverage, type-check-debt, where-matcher, release-rehearsal-clone, release-pending-publish) come from the .changeset path and the deletions. All were run. --ran warned STALE TREE: origin/main moved to c4526a7 (6 commits) during the run; none touches plugin-security or any file in this diff. CI on PR head 2fb7b36, read once at report time: Check Changeset, Check Documentation Links, Check PR Size, Flag docs affected by code changes, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, The card this PR closes must claim this branch → queued; Packed-tarball smoke (opt-in) → skipped. The five required contexts (Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core, Governed Surface Queue Guard) had not registered yet → in_progress.",
    "line_budget": "436 changed lines (+87 / -349), 6 files; under the 3,000-line human-merge threshold and inside the dispatch's 'a few hundred'. Per file: .changeset/15196-retired-catalog-residue.md +13/-0; per-organization-catalog.test.ts +0/-148; per-organization-catalog.ts +0/-28; position-catalog-refusal.test.ts +59/-95; position-catalog-refusal.ts +14/-77; scripts/check-logger-receiver-detach.mjs +1/-1.",
    "files_changed": [
    ".changeset/15196-retired-catalog-residue.md",
    "packages/plugins/plugin-security/src/per-organization-catalog.test.ts (deleted)",
    "packages/plugins/plugin-security/src/per-organization-catalog.ts (deleted)",
    "packages/plugins/plugin-security/src/position-catalog-refusal.test.ts",
    "packages/plugins/plugin-security/src/position-catalog-refusal.ts",
    "scripts/check-logger-receiver-detach.mjs"
    ],
    "deviations": [
    "My first gate pass at 2fb7b36 was discarded. Three families exited 3 (PREREQUISITE NOT MET): check-plugin-teardown-shape --self-test needed commit 621a487 (absent from the shallow clone), and check:dual-build-cjs-loads and check:i18n needed built output. The dist-reading gates in that pass may also have read a plugin-security dist/ built before my edits. Remedy: git fetch --depth=1 origin 621a487; a full turbo run build (cache replay, BUILD_EXIT 0); dist/index.mjs confirmed to hold HEAD's code (removed hint text: 0 hits; kept remedy text: 1 hit; new constraint spelling: 1 hit). The second full pass is the reading above: 88/88 exit 0.",
    "My first detached pnpm check:pm-dispatch-gates run did not capture its exit code. I re-ran it with the code captured (PMDG_EXIT 0). The uncaptured run is not counted.",
    "I opened the PR while the remote head was still 9501841: my local merge of origin/main (2fb7b36, one CLI-tests commit, disjoint) was unpushed. I pushed it immediately after, so the PR head is now 2fb7b36, the tree every reading names. The PR body was written once and not edited.",
    "I did not re-merge origin/main after it moved to c4526a7 during the gate run (6 commits; none touches plugin-security or this diff). §10 merges after a PR opens only on a reported conflict, a main-caused red or a queue removal, and CI runs the merge ref.",
    "Not a deviation, recorded for the check: commit trailers are the model-free pair AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named form. Labels: zero written, since the dispatch named none and a changeset exists (skip-changeset does not apply)."
    ],
    "mcp_calls": "0 — no MCP GitHub tool was called (reads used gh api single-card REST; writes went through the fleet-write relay)",
    "api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches x2, via scripts/pm/with-fleet.sh --via dispatch). They executed 3 writes as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft #24365; read back: 10635 bytes sent, 10635 stored, identical); POST /repos//issues/24365/assignees (os-steve, read back as listed); POST /repos//issues/15196/comments (this report). Plus 5 git pushes to the branch (empty probe, 35a9404, 7427cac, 9501841, 2fb7b36), which are not REST writes. Inside the budget: 1 draft-PR create, 1 of 3 comments, 0 PR-body edits.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed. packages/plugins/plugin-security/src/security-plugin.ts:4317 says the refusal fires for a position that 'names no sys_position catalog row', but the verdict reads the security catalog. This is comment drift with no reachable wrong answer, and it sits outside the claim's file surface. In the PR's Acceptance notes.",
    "carrier: none · noted, not filed. content/docs/permissions/system-context.mdx row 23b and position-catalog-refusal.ts module doc lines 44-49 still mention sys_position rows. Both remain true of rows left in an existing database. In the PR's Acceptance notes.",
    "carrier: C3 stage 9 (#23952) · noted, not filed. packages/plugins/plugin-sharing/src/bootstrap-declared-sharing-rules.ts:47 still points at the deleted per-organization-catalog.ts. It is left by dispatch exclusion; stage 9 retires that file."
    ]
    }


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    ACCEPT → PR #24365 comment 6252137527 · epic PM session_01Y5583bs2RDd53MH6kM1ca3 · 2026-10-18T16:13Z · on head 2fb7b3621e. It lands through the queue once every check on that head is green.

  15. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    Landed: PR #24365 · C2's last item · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-18T17:07Z

    reading value
    PR merged at 2026-10-18T17:06:23Z through the merge queue, merge commit 6a49efb9c4
    origin/main contains 6a49efb9c4; the queue branch gh-readonly-queue/main/pr-24365-… is gone
    content the 4 changed files are blob-identical to the accepted head 2fb7b3621e; per-organization-catalog.ts and its test are absent
    records seat ACCEPT 6252137527; no contract review owed (no contract face)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions