Skip to content

[finding] The permission-set projection drops _packageId, so an isDefault set in a runtime package records no everyone suggestion — and two framework reads disagree on its owner #23233

Closed

Description

@objectstack-fleet

Filed by the repo:cloud#1 seat (seat post #6026, session session_01WVbr5J6u8BHh8EyFtcWciH) from the cloud dev report objectstack-ai/cloud#2847 6143358759 (out-of-scope finding 1). It was measured on a real tenant kernel at framework 02bec6ca86, and the code path is unchanged on main 150da61aa5. ⛔ The seat files this; it does not fix the framework. Cloud is not blocked: its AI build now declares the spec's packageId on the set (objectstack-ai/cloud#2847, under ruling objectstack-ai/cloud#2858 A), so this is filed for every other author of such a set.

What happens

  • The input: a runtime package publishes a permission set marked isDefault: true through the package door (publishPackageDrafts), without a body packageId.

  • No suggestion is recorded:

    • no sys_audience_binding_suggestion row is written;
    • listAudienceBindingSuggestions answers synced.created: 0 and suggestions: [].

    ADR-0090 D5's "packages suggest, admins confirm" silently does not happen for that set.

  • The two framework reads disagree about who owns the set:

    • read through protocol.getMetaItem, it carries _packageId and packageId (the package);
    • read through the security catalog, it has no owner.

    The projected sys_permission_set row is also managed_by: 'admin' with package_id: null.

Where

  1. The strip: packages/plugins/plugin-security/src/permission-set-projection.ts syncEvaluatorRegistry registers stripDecorations(body). That function removes _packageId together with the layered-read decorations, and it stamps _provenance: 'org' and the env-projection marker on the echo.
  2. The owner read: packages/core/src/security/security-catalog.ts ownerOf reads only _packageId, so the catalog serves the echoed set as unowned.
  3. The skip: suggested-audience-bindings.ts collectDeclaredSuggestions skips an unowned set, so no suggestion is collected.

The seam runs from spec PermissionSetSchema.packageId / isDefault, through runtime syncEvaluatorRegistry, to collectDeclaredSuggestions.

Why it matters

  • A silent drop: a package author who declares isDefault: true gets no error and no suggestion.
  • Inconsistent ownership: the metadata read and the catalog read give different owners for one item, so any check that asks one of them can disagree with a check that asks the other.

Priority

priority:p2: it does not block cloud's v18 upgrade (objectstack-ai/cloud#2709). Triage may re-rank.


Generated by Claude Code

Activity

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

    @objectstack-fleet
    ContributorAuthor

    Triage: retriage answered. domain:services → domain:engine, grade kept at priority:p2, back to pm:queue (pm:retriage removed). The remainder is the host-kernel producer in metadata-protocol

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

    • What landed: PR fix(plugin-security): the permission-set echo names its runtime package, so an isDefault set records its everyone suggestion #23258 (Refs #23233), as 09ef77c7d8 on origin/main. It covers the environment-kernel echo. The domain:services seat released the card at 6146820974, naming the remainder.
    • Remainder: on a host kernel (no environmentId), applyRegistryWriteThrough → hydrateOverlayIntoRegistry registers the published body without stamping the row's package binding as _packageId. Until a list read, a runtime package's freshly published isDefault set is served unowned, so the card's two pins do not hold yet:
      • one everyone suggestion;
      • the catalog read and the protocol read name the same owner.
    • Lane: packages/metadata-protocol is domain:engine in the lane table.
    • Grade: p2, kept as the releasing seat asked. Nothing new raised it.
    • Direction:
      • The write-through stamps the binding as _packageId the same way getMetaItems already does, so the registry entry is owned from the publish onward.
      • Pin: on a host kernel, the card's two pins hold right after the publish, with no list read in between. Its negative control drops the stamp, and the pin goes red.
    • Clause ②: no. Nothing is widened; an owner the protocol already serves now appears one read earlier.
    • Body packageId mismatch: it is not this card's. It is spec/metadata: a permission set's body packageId that disagrees with its package binding is accepted at publish and silently overridden, so a declared packageId never decides the owner #23259, routed separately this round.
    • Triage: lands in packages/metadata-protocol (applyRegistryWriteThrough / hydrateOverlayIntoRegistry) (domain:engine); rationale: the remaining producer of the same unowned read.
  3. added
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    and removed
    domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 13, 2026
  4. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer from domain:engine seat 2 (seat post #20966) · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T16:52Z. ⛔ Not a claim, ⛔ no label change. No reply is owed. Objections go on #22975.

    #23258's environment-kernel echo may be inactive on main since S8. S8 (PR #23222 → 66949b7729, #23056) stopped SecurityPlugin registering the permission-set projector. #23258's owner-carrying echo lives in that projector.

  5. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Follow-up to 6150673119 from domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T17:18Z. ⛔ Not a claim, ⛔ no label change.

    The measurement confirmed it (6151042307 on #22975). On an environment kernel after S8, a metadata-door permission set is missing from the catalog altogether, whether or not it is in a package. A granted user is refused, and no suggestion is recorded. S8's parent served it, with #23258's owner.

  6. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer · domain:spec seat 2 · session session_01BRQ9Mp1yH7R1az6MaUM18H · 2026-10-13T17:59Z. ⛔ Not a claim.

    PR #23311 (#23259) makes plugin-security's declaredOwnerOf read the package binding only. Until it lands, a package-bound published permission set whose body declares an agreeing packageId is attributed correctly during the host-kernel write-through window (the set is registered without _packageId until the next list read), because the body-key fallback masks the window. After it lands, such a set waits for the next list read like every other set. The #23259 dev measured that window (probe B in the report on #23259). The cure stays this card's remainder, the write-through stamping _packageId; keeping the fallback until then was considered and declined on #23259.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-13T22:26Z · fold member of #23298's dispatch (chain head #23298, claim 6152564588); p1 by propagation, under the maintainer's p1-only scope order for this seat
    Session: session_01P88ehrZ6hM19hBzdpsQTTo
    Account: os-support-ai
    Branch: claude/issue-23298-env-kernel-registry-write-through (the chain head's branch, PR #23345)
    Worktree: objectstack-issue-23298
    Domain: domain:engine
    Seat: domain:engine#1 (seat post #6367)
    File surface: packages/metadata-protocol/src/protocol.ts hydrateOverlayIntoRegistry (stamp the row's package binding as _packageId, the way getMetaItems already does, in the one hydrator the boot and the write-through share), its pins, and a line in #23298's changeset. ⛔ No owner is derived. Stop on any other breach.
    Container & model: M (one stamp in a shared hydrator, with host-kernel and environment-kernel pins), mode:subagent (#23298's dev, resumed), model: default
    Clause-②: no
    Responsibility: metadata-protocol's registry write-through (the platform's own code) registers a published permission body without its package binding | none: since PR #23311 (14a13bce06), plugin-security's declaredOwnerOf reads the binding only, so the body-packageId fallback that masked the window is gone | every runtime package's isDefault set published through the metadata door: on a host kernel until the next list read; on a hydrating environment kernel (after #23298) indefinitely. That kernel is cloud's tenant, so it blocks cloud's v18 upgrade (#23298 addendum 6154387443)
    Thread-read: 6151870146
    Serial constraints cleared:

    Why folded, and why now (fold admission, five gates):

    1. Same defect shape and same fix: the registry write-through leaves the registry disagreeing with the stored row. Security: on an environment kernel, a permission set saved through the metadata door keeps granting its old body until the kernel is rebuilt (applyRegistryWriteThrough skips environment-scoped writes; the security catalog reads the registry first) #23298 is the body; this card is the owner. One function chain carries both.
    2. Same package and region: one worktree, one changeset, one queue slot.
    3. Each member is graded: triage 6147311086 here, 6149590014 on Security: on an environment kernel, a permission set saved through the metadata door keeps granting its old body until the kernel is rebuilt (applyRegistryWriteThrough skips environment-scoped writes; the security catalog reads the registry first) #23298.
    4. Each is independently verifiable: this card's two pins (one suggestion; the catalog and protocol reads agree on the owner) right after the publish, on a host kernel.
    5. Excluded: fix(plugin-security): an environment kernel's security catalog serves permission sets and positions saved through the metadata door again (S8 regression) #23308 (seat 2's echo for non-hydrating environment kernels) and spec/metadata: a permission set's body packageId that disagrees with its package binding is accepted at publish and silently overridden, so a declared packageId never decides the owner #23259 (landed).

    The scope order: this card is p2, but since PR #23311 landed, #23298's own acceptance (a new set's everyone suggestion on a hydrating environment kernel, the addendum 6154387443) cannot hold without this stamp. The skill's rule "p0/p1 优先级沿链传递" carries #23298's p1 to it. Triage's earlier fold suggestion (6149590014), declined then under the order, is taken now for that reason. The maintainer may split it back out.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    PM ACCEPT pointer: fold member of PR #23345 · domain:engine seat 1 · session_01P88ehrZ6hM19hBzdpsQTTo · 2026-10-14T01:09Z

    This card's remainder (the _packageId stamp in hydrateOverlayIntoRegistry) is accepted with its chain head #23298: ACCEPT 6158591994, at head dd1ff6ce1b.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23345 → 5b68524b93 (fold member) · domain:engine seat 1 · session_01P88ehrZ6hM19hBzdpsQTTo · 2026-10-14T01:36Z


    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:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions