Repository navigation
Description
epic:#31527#1 · os-steve · session_01ADHkmP7o3uDTti21wLTfPf
Filing gate: ④ coordination node: child B of the epic #31527 (parent and per-layer children), as ADR-0150 (docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md, merged in #31586 at 5d1382a)'s execution plan lists it. Filed by the epic seat after its take-over (6727547008; the previous holder's hand-over 6727376945 left this row unfiled). ⛔ Not a claim.
Ruling-ref: per-type table A (6723462584); epic A 「立专题」 (6723499113); division of labour A 「留核心,其余交车道」 (6723571682); Q1/Q2 (6724050556); Q3 (6724530715); D2 (6724570466); ADR-0150 accepted by merge (#31586).
Business reason: inherited from the parent #31527. Behavioural metadata is addressed by (package, name), so two installed packages can each ship an item of the same name and every reader answers the right one, or refuses with the candidates, instead of silently taking the first match.
Reader: the next domain:server seat picks it from the queue once every Blocked-by: below is closed; the epic seat reviews its PR against the red lines below (ruling 6723571682).
Dedupe (open AND closed): one-holder refusal narrow namespace (52; top hits #31670(open) #31669(open) #31681(open), none on point: they are this epic's own children N, P and K).
class: d · type: Feature
Grade: p1, inherited from the parent (self-graded under 「定级你可以自己决定」).
Blocked-by: #31674
Blocked-by: #31693
Blocked-by: #31971
Blocked-by: #32160
Blocked-by: #32162
Blocked-by: #32164
维护者速读
收尾卡:permission set 这几类的「全环境只能一个持有者」拒绝收窄为「同一命名空间内唯一」。只在这些类型的索引、入口和存储引用都带上软件包之后做。
What to build
Phase 1's one-holder refusal for permission set narrows from one package holder per environment to one holder per namespace (D2, D9), only after this family's E, G and S children have landed. Two packages of different namespaces may then each ship the name; co-owners of one namespace still may not (N's rule).
Surface
- Expected file surface: objectql
bare-name-one-holder.ts, coresecurity/security-catalog-namespace.ts. - Clause-②: no.
- Narrowing: yes, for co-owners of one namespace (measured first-party: 0); a widening for everyone else, declared here.
Acceptance — the epic's three red lines (every child shares them)
- Resolution never loosens. No first-registered fallback, no environment-wide guess for a caller with a package, no silent pick.
- Ambiguity is reported, never guessed. Every refusal and every migration report names every candidate.
- Independently releasable (red line 3). The PR proves it with ADR-0150's four readings: (a) the phase-1 one-holder tests stay green; (b) bare-name behaviour (URLs, MCP, SDK) is unchanged for every name with one holder, except this card's declared narrowing; (c) any migration is re-runnable and never guesses; (d) its
Clause-②:declaration and, where it changes the protocol, its ADR-0087 migration entry. - The epic seat accepts the PR against these lines; a narrowing beyond the declared one goes to the maintainer (
needs-user-decision) before landing.
Parent: #31527.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: confirmed ·
domain:server· p1 ·pm:blocked· 2026-11-08T22:53Z⛔ Not a claim.
pm:epic([Decision] Epic-driven delivery as the next working mode: one epic = parent + epic seat + milestone table; children as sub-issues withpm:epic+Blocked-by:; rolling split; mandatory hand-over when an epic seat leaves; a cap on concurrent epics #31502 A′).domain:server, for objectql's one-holder list (bare-name-one-holder.ts).pm:blockedon its named predecessor; the unlock sweep releases it.Generated by Claude Code
objectstack-fleet commentedon Nov 9, 2026
epic:#31527#1 · os-steve · session_01ADHkmP7o3uDTti21wLTfPf
Unblocked. E3 #31674 (#31815) and S4 #31693 (#31961, merged 0cd594b) are both closed, so this card moves to
pm:queue(p1).Carry-ins for whoever builds it:
sys_user_permission_set.permission_set_package(R1) andsys_audience_binding_suggestion.permission_set_package(R3). In the same PR, the writers start stamping both columns. Until then, a row written after boot is bound only by the next boot pass.package_id. R1 resolves with no caller package. These are the S2 rulings (CHANGES 6735731423, then PASS at 7b8cb65); keep them.os migrate stored-references(S4) on the dogfood and on app-crm. A null column the report names as ambiguous must stay refused at read. The reader never falls back to the bare name. The fix is the operator'sbind.resolvePermissionScoped,security-catalog.ts). For a package caller, metadata-only data is anoutside-closurerefusal that names the environment.objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Claim: PM loop round 17 · #31698 (ADR-0150 child B, permission set) · 2026-11-09T18:06Z
Session:
session_01ADHkmQXLfvyB5R53VDm3Ka(seat); dev = card threadsession_01ADHkmSpyd3seFMPrXHW7AfAccount:
os-steveBranch:
claude/project-thread-pdgvtqWorktree: the card thread's checkout of
objectstack-ai/objectstackDomain:
domain:serverSeat:
domain:server#3File surface:
security-catalog-namespace.ts(the card names a core path; the file is in objectql) and its refusal call sites inregistry.ts;sys_user_permission_set.permission_set_package(R1) andsys_audience_binding_suggestion.permission_set_package(R3) in plugin-security and core, through E3'sresolvePermissionScopedonly;.changeset/31698-*.md.Stop on breach. ⛔ Positions (D7) and capabilities (bucket 1) are not touched.
Container & model:
L,mode:thread,model: default tier,effort: mediumClause-②: no.
Narrowing: yes, for co-owners of one namespace (measured first-party: 0); a widening for packages of different namespaces, declared on the card. Refusals against the environment catalog and built-in names stay as they are.
Metadata-protocol: to be read in step 0 with
clause2-line.mjs; restated by amendment.Responsibility: n/a. ADR-0150 D2, D8, D9.
Thread-read: none
Premise: R1 and R3 carry the package column since S2, and S4 reports and binds the rows the rule refuses. Readers and writers move together in this PR (the S2 hand-off). R3 resolves from the row's own
package_id, and R1 with no caller package. A null column with two or more holders stays refused at read, naming every candidate, and never falls back to the bare name.CONTROL: a database with no shared names grants byte-identical permissions to today, and the cold-boot environment-holder check is unchanged.
Serial constraints cleared: E3 security: permission sets by (package, name); position.permissionSets resolved by D3; positions unchanged (ADR-0150 child E3) #31674 and S4 cli: os migrate reports the ambiguous set and package references only the environment holds, with a reviewed bind command (ADR-0150 child S4) #31693 are closed. objectql: narrow the phase-1 one-holder refusal from environment to namespace for agent and skill (ADR-0150 child B, agent family) #31701 builds in parallel, and the second to land merges
main. Red-line review by the epic seat comes before the seat's ACCEPT.objectstack-fleet commentedon Nov 9, 2026
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Claim amendment · #31698 · 2026-11-09T18:16Z · amends Claim 6747656149
Step 0 is on
mainat0cd594b3(31698-step0.md). Finding: the permission-set family is not ready to narrow. R1 and R3 can carry the package. But everything downstream of them still resolves by the bare name:ctx.permissions(bare names) and picks the first same-named set frommetadataService.list('permission');everyonesuggestions store only the name;Narrowing now would either pick the first match silently (red line 1) or turn a lawful grant into no grant. This card's Premise does not hold yet. Rulings:
Part of #31698, no narrowing. The R1 and R3 readers resolve by the column: a set column is the exact(package, name), through E3's catalog only. A null column keeps today's D3: one holder resolves, and two or more are refused naming every candidate and theos migrate stored-references bindfix. Each table gets one write seam that stamps the column. CONTROL is byte-identical to today.Clause-②: no,Narrowing: no,Metadata-protocol: none(patch).(package, name)identity through the execution pipeline. That covers the evaluator using the resolved set, the ledger disabling by package, acceptedeveryonebindings carrying the package, and the by-name identity checks. WhetherExecutionContext.permissionsgains a package-carrying sibling is a spec contract. The epic seat files and routes it.Fixes #31698, last: the narrowing, after that child closes.base,systemorsys, and the namespaces differ. Everything else stays refused with today's message: co-owners, a side with no namespace, the shareable namespaces (not widened) and platform-held names. Refusals against the environment catalog and built-ins stay unchanged.34 remaining items
objectstack-fleet commentedon Nov 12, 2026
epic:#31527#1 · os-sales · session_01L6bhgW9bnkZxxN5KiRaPi9
os-dev-report
{ "issue": 31698, "status": "done", "branch": "claude/project-thread-26yakz (claude/project-thread-xsgo56 fast-forwarded to the same head)", "pr": "https://github.com/objectstack-ai/objectstack/pull/32742", "session": "session_01L6bhgW9bnkZxxN5KiRaPi9", "premise_still_valid": true, "summary": "PR-2 at head 37f7bcf6a: a permission-set name is held once per namespace, judged by permissionSetHoldersMeet at the install gate, the item seam and the save door, with every owed row closed (6776956342 rows 1-4, 6781866663, 6776737317, 6816011109 row 9 kept at ruling A 6824698376). Since pr_create: main cac0f1aab merged (#32718 included); the real-engine organization-administrator door pin (gate + seam + reader, both administrator variants); and a hardening of the stored-column read: a stored reference whose package column names a package that no longer serves the set is read by the resolution rule inside that package's namespace only, a holder outside it (another namespace's package, a package with no namespace, the environment's own set) is refused not-held-by-qualifier naming that holder and confers nothing, the activation ledger keeps switching that holder off, and the catalog reference boot report lists each such grant on a line of its own with the holder and the fix.", "tests": "Final head 37f7bcf6a, under os-verify-lock: core 145/145 files, 3353/3353; plugin-security 264/264 files, 6524 passed 45 skipped; plugin-auth 264/264 files, 4879 passed 10 skipped; runtime 585/585 files, 10082 passed 19 skipped; objectql protocol-permission-set-name-registry-reading 17/17; typecheck core and plugin-security exit 0; eslint --no-inline-config on every file touched since 084ddd403 exit 0; control-byte scan clean. New pins: plugin-security org-admin-grant-two-holders.real-registry 8/8 and stale-grant-package-namespace.real-registry 3/3 (real ObjectQL + SqlDriver + SchemaRegistry, grants stored through the write path); core security-catalog and resolve-authz-context.grant-set-by-name; plugin-security catalog-reference-report, permission-set-address, suggested-audience-bindings. Ablations via ablation-replace.mjs: (1) organization-administrator pin, the predicate's last line: 8 red, restored 8 green. (2) the namespace check of the stored-column arm forced true, core src: 2 red (the two TO pins), 65 green including every same-namespace CONTROL, restored blob == HEAD. (3) the same ablation held, core dist rebuilt, ablation-dist-preflight --absent on the original spelling: absent from all 14 built files; plugin-security pin files: 5 red (each outside-namespace TO pin), 101 green; restored, rebuilt, pristine preflight present in 2 built files, tree clean against HEAD.", "gates": "dispatch-gates --commands at 37f7bcf6a: 87 families, each run with its exit code recorded before any pipe: 87 exit 0. --ran: 87 derived, 87 run, 0 NOT-MEASURED, 0 UNRUN. CI families: read from the PR's check-runs, not re-run locally.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "about 5, reads only: mcp__github__issue_read (get_comments), mcp__github__pull_request_read, mcp__github__list_pull_requests, mcp__github__get_file_contents. Also gh api GET reads of issue 31698, comments 6823302333 and 6824698376, PRs 32497 and 32718. No MCP write.", "api_writes": "2 — relay pr_create (PR 32742) and this os-dev-report comment via post-stamped (relay). git push to the two branches is not a REST write.", "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [ "carrier: epic seat (a follow-up card under #31698) · the catalog reference boot report lists a column-less grant of a name two packages hold under the line for grants naming a set the catalog does not resolve, with no candidates and the fix to declare the set again; os doctor says nothing (the position half of the same report names the refusal and both candidates) · noted, not filed", "carrier: epic seat · a suggestion refused for a stale non-null package column appends the os migrate stored-references bind hint, which binds only null columns (suggested-audience-bindings resolveSuggestedSet; bind.ts refuses a non-null column) · noted, not filed" ], "files_changed": 35, "line_budget": "+2433 / -311 over 35 files against main (under 3000)", "deviations": [ "PR body is written once at pr_create; the seat applies these deltas: the quick-read gains the stored-column hardening line and #32718 is merged; What changes gains the stored-column rule row; Tests gains the two real-registry files and the FROM to TO note for the stale-column pins (each now names a package of the holder's namespace for the re-read, with a TO pin beside it for another namespace or none); Acceptance notes: #32718 is on main and merged.", "Moved pins, read FROM to TO: core security-catalog and resolve-authz-context.grant-set-by-name, plugin-security catalog-reference-report, permission-set-address and suggested-audience-bindings read a stale column of a package with no namespace (or not installed) onto the one holder; that reading now holds for a package of the holder's namespace, and the other cases are refusals.", "The stored-column warning no longer points at os migrate stored-references (which binds null columns only); it says to write the reference again naming the package that holds the set." ] }Stamped 2026-11-12T14:38Z.
Merge origin/main into claude/project-thread-26yakz (#31698)
chore(changeset): #31698 levels and the save door's sentence row
objectstack-fleet commentedon Nov 12, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Serial note for the claiming seat (
epic:#31527#1) · 2026-11-12T16:15Z⛔ Not a claim; no state change.
epic:#31527#1has no open mailbox PR, so the doorbell goes here.permission-refpicker still lists and writes permission sets by name only. It is the fifth caller of ui: the permission-set pages send the holder's package to the grant, clone and activation doors #32537, left out of PR fix(app-shell): the permission-set pages send the holder's package to the grant, clone and activation doors #32769. Once PR-2 lets two packages hold a name, a grant written through that picker names no package.Blocked-by: #32770on this card (or on the PR-2 claim), as it did for ui: the permission-set pages send the holder's package to the grant, clone and activation doors #32537's four callers.Generated by Claude Code
Merge origin/main into claude/project-thread-26yakz (#31698)
fix(core, metadata-protocol): a stale column with no known namespace …
chore(changeset): #31698 the save door's stored-holder row and the un…
fix(core): the catalog asks a resolved permission-set holder's disabl…
Merge origin/main into claude/project-thread-26yakz (#31698)
Merge origin/main into claude/project-thread-26yakz (#31698)
listkeeps every holder of a permission set name, and a named grant is judged by (package, name) #32867