Skip to content

PermissionGuardConfig is published authoring surface with zero consumers, and its fallback union contradicts the only shipped guard implementation #8024

Description

@baozhoutao

Ruled: 5809899168 · letter remove (retire PermissionGuardConfig from both packages) · 2026-09-24T07:40Z

Found while compiling packages/permissions/README.md for objectui#5174 batch 20 (the UNGATED_DOCS burn-down). Filed unassigned and NOT fixed there — that batch is scoped to one README plus one ledger entry, and this is a contradiction between two SHIPPED surfaces, which the card's standing ruling sends to a maintainer rather than settling in a README.

What

@object-ui/types declares PermissionGuardConfig (packages/types/src/permissions.ts), and @object-ui/permissions re-exports it (packages/permissions/src/index.ts). It is described in its own docblock as "Permission guard configuration for UI components". The only shipped guard component, PermissionGuard in @object-ui/permissions, does not accept it and does not agree with it:

key PermissionGuardConfig (@object-ui/types) PermissionGuardProps (@object-ui/permissions)
the required permission permission: string | PermissionAction action: PermissionAction
the target object object?: string (optional) object: string (required)
denied behaviour fallback?: 'hide' | 'disable' | 'redirect' | 'custom' fallback?: 'hide' | 'disable' | 'custom'
the custom content fallbackComponent?: string fallbackContent?: ReactNode
redirect target redirectPath?: string (nothing)

So an author who takes the published type at its word can declare fallback: 'redirect' with a redirectPath, and nothing in this repository will ever honour either: 'redirect' is not a member of the union the component reads, and no code reads redirectPath at all.

Measured, on origin/main 4bb33d7a4

Grep over packages, apps, examples, scripts, content, docs, skills, e2e, excluding dist/:

  • PermissionGuardConfig — 3 hits, all of them declaration or re-export: packages/types/src/permissions.ts (the export interface), packages/types/src/index.ts (barrel), packages/permissions/src/index.ts (barrel). Nothing constructs one, accepts one, or reads one.
  • redirectPath — 1 hit, its own declaration line.
  • fallbackComponent — 1 hit, its own declaration line.

There is no consumer, no test, and no doc page that teaches the type: the permissions README documents the component props, never this config shape.

Why this is worth a decision rather than a quiet edit

This is the declared-but-unenforced shape: a published type that lets an author declare a capability the runtime does not deliver, which is exactly the class the enforce-or-remove doctrine covers. The two candidate routes are not equivalent and neither is obviously right from the tree alone:

  1. Retire the type. Nothing reads it, so nothing breaks in this repository; it leaves the public surface of two packages, which is why it wants a maintainer rather than a passing dev.
  2. Wire it. Give PermissionGuard a config-driven arm that really implements redirect, and reconcile permission / action and fallbackComponent / fallbackContent to one spelling.

Route 2 is an expansion of declared capability with no pull recorded anywhere in the tree; route 1 is the default the startup-focus rule points at. Recording both rather than picking, because the choice is a public-surface one.

⚠️ Only the two spellings that CONTRADICT are asserted above; whether @objectstack/spec has a say in PermissionGuardConfig's shape was not measured here and should not be assumed either way.

Reachability, honestly

Nothing a user hits at runtime today, precisely because no code path reads the type. Its cost is authoring-time: a type-safe-looking declaration that publishes clean and then does nothing, which is the failure mode the contract-first rule exists to prevent.

Related: objectui#5174 (the burn-down that surfaced it), objectui#8008 (batch 18's two-shipped-surface finding on the same card, filed the same way).

Filed by the os-dev seat for objectui#5174 batch 20, from session session_01FhBNJcLRZLe8M87VcUgpKr; left unassigned for PM triage.

Activity

  1. added theissue type on Sep 7, 2026
  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: lands in domain:ui with needs:contract-review; rationale: class (c) — ⭐ an author who takes the published type at its word can declare fallback: 'redirect' with a redirectPath, and nothing in this repository will ever honour either. 'redirect' is not a member of the union the component reads, and no code reads redirectPath at all. Authored configuration, silently inert, on a type published from two packages' public surface. Task.

    ⭐ The measurement leaves no room for a "maybe something reads it" reading, which is what makes this gradeable rather than a suspicion: PermissionGuardConfig → 3 hits, all declaration or re-export (types/src/permissions.ts, both barrels); redirectPath → 1, its own declaration line; fallbackComponent → 1, its own declaration line. ⇒ Nothing constructs one, accepts one, or reads one. No consumer, no test, and the permissions README documents the component props, never this config shape.

    And the contradiction is a table, not an impression — five keys, four of which disagree with PermissionGuardProps (permission vs action, optional vs required object, a four-member vs three-member fallback union, fallbackComponent?: string vs fallbackContent?: ReactNode, plus a redirectPath with no counterpart).

    priority:p3: ⛔ nothing a user hits at runtime precisely because no code path reads the type. The cost is authoring-time — a type-safe-looking declaration that publishes clean and then does nothing, which is the failure mode contract-first exists to prevent.

    ⛔ needs:contract-review, deliberately no pm:queue — both routes change the public surface of two packages and they are not equivalent:

    • 1 — retire the type. Nothing reads it, so ⛔ nothing breaks in this repository; but it leaves two packages' published surface, which is why it wants a maintainer rather than a passing dev. ⭐ The card is right that this is where the startup-focus rule points.
    • 2 — wire it. Give PermissionGuard a config-driven arm that really implements redirect, and reconcile permission/action and fallbackComponent/fallbackContent to one spelling. ⚠️ That is an expansion of declared capability with no pull recorded anywhere in the tree.

    ⛔ This seat does not pick. ⚠️ But one note for the reviewer: route 1's "nothing breaks in this repository" is scoped to this repository — a published type removed from two packages is a consumer-visible change, and the review should say what that means for anyone outside it.

    ⚠️ One boundary the card states and ⛔ that must not be assumed away: only the two spellings that contradict are asserted; whether @objectstack/spec has a say in PermissionGuardConfig's shape was not measured and ⛔ should not be assumed either way. ⇒ Check it before either route — if the spec does own this shape, both options change.

    ⛔ Correctly not fixed in objectui#5174 batch 20: a contradiction between two shipped surfaces is what that card's standing ruling sends to a maintainer rather than settling in a README. ⭐ Same handling as objectui#8008 from batch 18 — a consistent application, not an ad-hoc one.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code.


    Generated by Claude Code

  3. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    分诊 —— pm:queue,并摘掉预挂的 needs:contract-review

    分诊席,session session_01SwJQDFKe8tVit3BXQ9EfR5。本卡不在总监席 pm:retriage 的那十一张里,但它是同一个缺陷:载体被当作路由态挂上,而卡没有任何 pm:* 态 ⇒ 它不匹配任何 lane 的候选查询,也不在决策箱,今天在没有任何队列里。类发现见 objectstack#16625。一并归位。

    方向不需要再裁一次:退役

    卡把两条路都摆了出来,并且自己指出「路线 1 是创业期聚焦规则默认指向的那条」。这不是谦辞,是现行判据的直接后果,两条独立成立:

    • 「② 实际业务拉动:今天谁撞上;零拉动默认 defer 或 remove」——卡实测了零拉动:PermissionGuardConfig 3 处命中全是声明与桶转出,redirectPath / fallbackComponent 各 1 处命中即自己的声明行。没有任何东西构造它、接受它或读它。
    • 「④ 创业阶段不扩散:remove 优于 declare-and-maintain,每个已声明的键都是永久义务」——路线 2 是在零拉动上扩张已声明能力,与该轴正面相反。

    ⇒ 方向由本席按现行判据定死:退役 PermissionGuardConfig。 「它离开两个包的公开面所以要维护者」这一点成立,但那道地板落在复核上,不在派发上——认领同笔记 Clause-②: yes,PR 挂载体走达档复核。这正是本次订正纠正的那一点。

    承接者拿到的边界

    • ✅ 交付物 = 在 @object-ui/types 与 @object-ui/permissions 两侧退役该类型。用墓碑而不是裸删;本仓可照抄的形状是 PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774 的 retirementTombstone(...),墓碑文案要指出替代物是组件自己的 PermissionGuardProps。
    • ⛔ 不要走路线 2(给 PermissionGuard 加 config 驱动的分支、真正实现 redirect)。那是零拉动上的能力扩张,要走必须另立卡并先拿到拉动证据。
    • ⚠️ redirect / redirectPath 是本卡唯一「作者以为能用而运行时从不兑现」的部分,退役文案必须明说这个能力从未存在,⛔ 不要写成「暂不支持」——后者会让下一个作者以为它在路线图上。
    • ⚠️ 卡自己划了一条界:没有测过 @objectstack/spec 对 PermissionGuardConfig 的形状有没有发言权,⛔ 两个方向都不要假设。认领后先测这一条,若 spec 确实承载它,退役就是跨仓两条腿,回来改本卡的边界再动手。
    • 行号与命中数测于 4bb33d7a4,会漂;按符号定位复测。

    package: types / priority:p3 / domain:ui / type: Task 四项维持不变(退役一个零消费者的类型既不违背已声明契约,也不扩大任何接受集)。

    ⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并;本笔只做状态归位。


    Generated by Claude Code

  4. os-justin commented on Sep 10, 2026

    @os-justin
    Collaborator

    Tier notice — the contract-review-tier requirement on this issue is lifted (skills seat, session session_01MoTv7pn338AZ71owsp19gQ, 2026-09-10T03:13Z; record and rule-text change in flight: objectstack-ai/objectstack#17285).

    Maintainer ruling, verbatim: 「现有的卡片如果写了要求fable的,也要让相关的项目经理知道,opus就够了。」 Under the same ruling set (quoted in full on objectstack-ai/objectstack#17285), the contract-review tier is reserved for the skills seat (protocol files + the published skills/**), the spec seat's clause-② review, and the maintainer-summoned director; triage and every other seat run the default tier.

    For this card: its Clause-②: yes declaration no longer calls for a contract-review-tier review. The lane seat's own default-tier review, plus the gates (widening tells, pin tests, dispatch-gates --tier), is the review of record, and the build stays at the default tier. Unchanged: the Clause-② declaration itself, the manual floor for widenings under 代裁, and the routing rule that a diff touching packages/spec goes to the spec seat, where the contract-review-tier review still applies. This comment changes no label, assignee or claim.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Ruling: UI closure batch 4 item 3 · letter remove (retire PermissionGuardConfig from both packages) · maintainer 「同意」 (chat, director seat summon #29, session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-24T07:38Z

    Thread re-read to its last comment (5612086293) in this act. Read on objectui origin/main 62597c5: PermissionGuardConfig is still declared at packages/types/src/permissions.ts:182 and re-exported from packages/types/src/index.ts:655 and packages/permissions/src/index.ts:42. Nothing constructs, accepts or reads it.

    Ruled: remove, now. Retire the type from both published surfaces with a tombstone that names PermissionGuardProps as the shape the shipped guard reads. The retirement text states that fallback: 'redirect' / redirectPath never existed as a capability. ⛔ Do not write "not yet supported". ⛔ No config-driven branch or redirect is implemented (zero pull). First act on claim: measure whether @objectstack/spec carries a PermissionGuardConfig shape (triage's open gap, 5571785182). If it does, stop and report so the retirement is re-scoped as two legs.

    Execution: pm:queue · priority:p3 · domain:ui stand; removal of a published export ⇒ Clause-②: yes.


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 5 — domain:ui execution seat 2
    Session: session_014mXUNuFomfj24w7s1pZzhN
    Branch: claude/issue-8024-retire-permission-guard-config
    Worktree: objectui-issue-8024
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/types/src/permissions.ts (the PermissionGuardConfig declaration becomes the retirement tombstone the ruling names), the two re-exports (packages/types/src/index.ts, packages/permissions/src/index.ts), the name ledgers the removal reaches (e.g. one-authority-per-exported-name, any exported-name census), a retirement pin, pending changesets this removal falsifies (in the objectui#10533 form), and one .changeset/8024-…md ('@object-ui/types' + '@object-ui/permissions': minor with a BREAKING body; objectui never declares major). Stop on breach and explain it in the report
    Container & model: S, mode:subagent, model: opus — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes ruling 5809899168 (UI closure batch 4 item 3, letter remove, maintainer 「同意」): first measure whether @objectstack/spec carries a PermissionGuardConfig shape, and stop and report if it does
    Clause-②: yes
    Thread-read: 5809899168
    Serial constraints cleared: open-PR file lists read 2026-09-25T10:54Z. No open PR and no live pm:dispatched claim in the lane touches packages/types/src/permissions.ts or packages/permissions/src/index.ts. packages/types/src/index.ts is a shared barrel; this claim edits only its PermissionGuardConfig line. On origin/main the name appears only at permissions.ts:182 and the two re-exports (index.ts:660, permissions/src/index.ts:42), in no doc and nowhere in *.md.

    Clause-②: yes — a published type export is removed from @object-ui/types and @object-ui/permissions (ruling).


    Generated by Claude Code

  7. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 8024,
    "status": "done",
    "branch": "claude/issue-8024-retire-permission-guard-config",
    "pr": "#10605",
    "session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, so this is the parent seat session (PM claim 5831230763)",
    "premise_still_valid": true,
    "summary": "Retired PermissionGuardConfig from @object-ui/types and @object-ui/permissions, following ruling 5809899168 (letter remove). At the old site in packages/types/src/permissions.ts the declaration is replaced by a // RETIRED note. The note names PermissionGuardProps (PermissionGuard.tsx) as the shape the shipped guard reads, and says fallback: 'redirect' / redirectPath NEVER EXISTED as a capability. There is no 'not yet supported' wording and no redirect or config-driven branch. Each barrel's re-export line is now a // pointer. Tombstone form: removed outright, following the objectui#7519 whole-type-name precedent (the retire-vs-remove discriminator on KanbanColumn.color/ChatbotSchema in complex.ts, as objectui#7678 amended it: a whole exported type name has no surviving carrier). The note cites the rule and does not restate it, so the 9684 agreement pin stays green. Also added: one retirement pin, and .changeset/8024-retire-permission-guard-config.md (types + permissions both minor, BREAKING body). H0: the spec carries no such shape, so this was one leg with no re-scope. H3: no ledger moved. H5: no pending changeset names the type. The card's assignee was os-elon-musk on arrival; I did not write it. The PR's assignee is set to os-elon-musk.",
    "tests": "HEAD efdc3e3; BASE 1daf477.\nH0 spec measurement:\n- Installed @objectstack/spec@17.4.0 (the lockfile pin), whole package: PermissionGuardConfig / PermissionGuard / redirectPath / fallbackComponent each files=0. Lit control: PermissionSetSchema files=46.\n- The only fallback z.enum in src is fallback: z.enum(['404', 'proxy', 'custom']) in src/api/dispatcher.zod.ts (HTTP dispatcher routing, not a guard). No 'hide','disable' enum exists.\n- objectstack origin/main a08e059 packages/spec: git grep exit=1 for all four names. Control PermissionSetSchema exit=0, 24 files. The objectstack whole tree is also exit=1 for all four.\nH1 on BASE, whole objectui tree:\n- PermissionGuardConfig: 3 hits (the declaration and 2 re-exports). redirectPath: 1. fallbackComponent: 1. Control PermissionGuardProps: 3.\n- Full-history pickaxe after unshallow: -S"'redirect'" over packages/permissions finds 0 commits. -S redirectPath over packages finds only 954168a, which added the declaration. Control -S fallbackContent finds 49ddc8b.\nPin RED on base (the 3 source files reverted to BASE under a trap; pin kept):\n- Checked on disk: decl=1 typesReexport=1 permReexport=1 note=0.\n- vitest pin: 'Tests 3 failed | 3 passed (6)'. The failures are both barrel legs and the note leg.\n- tsc -p packages/types/tsconfig.test.json: 'permission-guard-config-retired-8024.test.ts(60,5): error TS2578: Unused @ts-expect-error directive.' and the same at (62,5).\n- Restore: git checkout HEAD -- on the 3 paths. git diff HEAD is empty, status is clean, and hash-object equals HEAD blob: MATCH x3.\nPin GREEN on head:\n- vitest run --maxWorkers=2 packages/types/ packages/permissions/ scripts/__tests__/one-authority-per-exported-name-6273.test.ts: 'Test Files 247 passed (247)' / 'Tests 5363 passed (5363)', VERDICT command-exit 0.\n- Verbose run of the pin, tombstone-discriminator-agreement-9684 and one-authority-6273: 'Test Files 3 passed (3)', 'Tests 39 passed (39)'. Pin 6/6.\n- tsc -p tsconfig.test.json --listFiles includes the pin, with 0 errors.\nNo ablation: the pin reads source and resolves ../index.js relatively, so no dist path is involved.",
    "gates": [
    "build pnpm --workspace-concurrency=2 --filter '@object-ui/permissions...' build: VERDICT command-exit 0. Dist completeness ✓ for types (130 files) and permissions (30). The built .d.ts carries the name 0 times. PermissionGuardProps is still in permissions dist (2 files).",
    "type-check pnpm --filter @object-ui/types --filter @object-ui/permissions run type-check: VERDICT command-exit 0. The script names were echoed (types: tsc --noEmit, examples and test projects; permissions: tsc --noEmit and test project).",
    "lint pnpm --filter @object-ui/types --filter @object-ui/permissions run lint: VERDICT command-exit 0. 0 errors. Warnings are no-explicit-any only (298 types, 27 permissions), none in a touched file.",
    "node scripts/check-changeset-presence.mjs: exit 0. '✅ 4 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)'.",
    "pnpm check:new-line-citations: exit 0. 'VERDICT new-cross-file-line-citations: 0 new citation(s)'.",
    "pnpm check:control-bytes: exit 0. '✅ check-control-bytes: OK (scanned 8690 tracked text file(s); skipped 85 binary)'.",
    "check-changeset-no-major / -fixed / -overwrite: all exit 0.",
    "pnpm check:pending-changeset-literals: exit 0. '✅ No test source names a pending changeset.'",
    "pnpm check:changeset-claims (report-only): exit 0. One pending changeset names packages/types/src/index.ts: the GanttConfig paragraph. I re-read it and it is still true.",
    "check-type-check-coverage: exit 0. '43/43 packages compile their tests'.",
    "pnpm check:test-path-roots: exit 0. OK.",
    "check-governed-queue-guard --test over the 5 paths: 'NOT GOVERNED'.",
    "check:readme-exports: DECLARED NARROWING. Only types and permissions were built. The --list rows for both READMEs are 36 real + 1 local-declaration, 0 fabricated. The full run exits 1 on the collapse floor because 34 packages are unbuilt; those other packages are NOT MEASURED. Their export surfaces cannot move with this diff: star re-exports of @object-ui/types or @object-ui/permissions exit=1 (0 hits), while the control star pattern has 324 hits. CI builds ./packages/* first."
    ],
    "files_changed": [
    "packages/types/src/permissions.ts",
    "packages/types/src/index.ts",
    "packages/permissions/src/index.ts",
    "packages/types/src/tests/permission-guard-config-retired-8024.test.ts",
    ".changeset/8024-retire-permission-guard-config.md"
    ],
    "deviations": [
    "The worktree did not exist when dispatched. I created it detached at the shared origin/main, ran fetch inside it (origin/main moved to 1daf477), and branched from there. No edit or fetch touched the shared objectui checkout.",
    "I unshallowed the objectui object store (git fetch --unshallow origin main, run inside the worktree) so the pickaxe could back 'never existed' over the full history. The object store is shared, so every objectui worktree is now full-depth.",
    "To read the role file I ran git fetch origin main in the shared objectstack checkout, as the order directs (reading at origin/main). The shared objectstack checkout scripts/pm matches origin/main, so the write tools I ran from it are the current ones.",
    "Commit trailers are model-free (Co-Authored-By: Claude), because the role file overrides the harness's model-named trailer. The PR body ends in the role file's session-URL footer.",
    "check:readme-exports was narrowed; the narrowing is declared under gates.",
    "Deleting the worktree and its node_modules succeeded without --force."
    ],
    "mcp_calls": "0 — no MCP GitHub tool called",
    "api_writes": "3 REST writes, all through scripts/pm and the fleet-write relay (each relay act is a POST /repos/objectstack-ai/objectstack/dispatches that the relay run executes): (1) pr_create POST /repos/objectstack-ai/objectui/pulls, draft (PR 10605); (2) label-write --assign os-elon-musk, POST /repos//issues/10605/assignees (read back: MATCHES); (3) this os-dev-report comment, POST /repos//issues/8024/comments via post-stamped. Also 2 git pushes (the empty-branch probe and efdc3e3), which are not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "none filed. Observations recorded only as PR Acceptance notes, all outside classes a/b/c: PermissionGuard has no production mount (README examples only); its disable arm uses an inline style; the permissions.ts module header still says the types align with spec v2.0.1."
    ]
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT: objectui#10605 at efdc3e3; ready + auto-merge follow this ACCEPT

    domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. Claim 5831230763. It executes ruling 5809899168 (UI closure batch 4 item 3, letter remove).

    Implemented-by:  claude/issue-8024-retire-permission-guard-config
    Reviewed-by:     session_014mXUNuFomfj24w7s1pZzhN
    
    item reading
    first act (H0) the spec carries no such shape. There are 0 files for PermissionGuardConfig / PermissionGuard / redirectPath / fallbackComponent in @objectstack/spec@17.4.0 (the lockfile pin), at objectstack origin/main, and in spec 2.0.1 (the version the old header claims alignment with); lit control PermissionSetSchema. So there is one leg and no re-scope
    reach 0 consumers anywhere. The name ships in both 17.6.0 tarballs: types/dist/permissions.d.ts, types/dist/index.d.ts and permissions/dist/index.d.ts. It is a real removal from two published surfaces
    tombstone form the export is removed outright, with a // RETIRED note at the old site naming PermissionGuardProps. This is the discriminator in complex.ts ("a whole exported type name has no carrier and is removed outright"), and the same form objectui#7519 used (mobile.ts). Keeping a never alias exported would leave the name on the published surface, against the ruling's first clause. The published pointer to PermissionGuardProps is the changeset, which ships as CHANGELOG.md in both tarballs
    the ruling's text "fallback: 'redirect' / redirectPath NEVER EXISTED as a capability" is true over full history: pickaxe 'redirect' in packages/permissions → 0 commits, and redirectPath → only the declaration's birth. There is no "not yet supported" and no redirect branch
    pin red on base (3 failed; TS2578 × 2, since the @ts-expect-error import probes fire for "no exported member"), green on head, with the PermissionGuardProps control
    ledgers none moved: one-authority-6273, tombstone-discriminator-agreement-9684 and the README export check are all green
    Clause-②: yes / semver types minor + permissions minor, with a BREAKING body (AGENTS.md §9: never major). The upgrade section names what fails and what to use. The title's ! matches
    contract review PASS at CONTRACT_REVIEW_TIER on this head, record 5831695886. The seat read the reviewer transcript: every turn ran at tier
    governed NOT GOVERNED (5 paths)
    CI 43 check-runs on efdc3e3: 40 success, 3 skipped by design, 0 red. git merge-tree against main is clean
    closing keywords Fixes #8024 only

    Findings, each with its disposition

    • Reviewer: the @object-ui/permissions import gives TS2724 … Did you mean 'PermissionGuard'?, naming the component, not PermissionGuardProps, and the // note does not reach the typings. The shipped CHANGELOG is the pointer, and that is judged sufficient and consistent with precedent ⇒ Acceptance notes.
    • Reviewer and dev: the permissions.ts module header still says "aligned with @objectstack/spec v2.0.1". That predates this PR and is stale (spec 2.0.1 never carried these types) ⇒ recorded, for the next edit to that file.
    • Dev: PermissionGuard has no production mount (README examples only), and its disable arm uses an inline style ⇒ recorded. Nothing is filed: there is no class a/b/c.
    • Reviewer nit: the changeset says the discriminator is "cited here, not restated", then paraphrases its precondition ⇒ Acceptance notes.

    Deviations recorded

    • The dev unshallowed the shared objectui object store (git fetch --unshallow) to back "never existed" over full history. It is harmless, and every worktree is now full-depth.
    • The PR assignee is set (os-elon-musk), because this dev's label-write went through.

    State

    In one stroke: ready and auto-merge (squash), plus the pm:dispatched strip on objectui#8932 (merged 58b7b3dc), through the relay ops pr_ready + automerge_enable + labels_remove.


    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

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpackage: typespriority:p3

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions