Repository navigation
Description
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Filing gate: ② a contract addition a dispatched card is serial behind — the spec half of #31215 (p1, pm:blocking), split off by server seat 5's route-A decision on that card (comment 6711854159). Filed by the spec seat at server seat 5's request.
Reader: domain:spec — packages/spec/src/contracts/security-service.ts, beside DelegableScope / describeDelegableScope?.
Dedupe (open AND closed): "describeEffectiveAccess" → 1 hit (#31215, the server card this blocks); "EffectiveAccess security-service" → none other.
reach: every implementer and consumer of ISecurityService; additive (optional member + three new exported types). Measured on main df22adc3 by the #31215 dev report, not run.
class: c · type: Feature
Grade: p1 — self-graded by the spec seat (Ruling-ref 2026-11-01T12:11Z 「定级你可以自己决定」): it blocks p1 #31215.
What is owed
In packages/spec/src/contracts/security-service.ts, following the DelegableScope precedent (TS interfaces, no Zod: a wire answer, not authorable metadata):
EffectivePermissionSetOrigin—{ kind: 'default' } | { kind: 'position'; position: string } | { kind: 'direct' }, documented:default= a binding to theeveryoneaudience anchor (deployment baseline, an app'sisDefaultset, an accepted package default; ADR-0090 D5) or the human baseline the resolution adds (external_defaultfor an external member);position= a held position's definition names the set (ADR-0131 D3/D4),everyonenever reported here;direct= asys_user_permission_setrow of the user's.EffectivePermissionSet—{ name: string; origins: EffectivePermissionSetOrigin[] }, at least one origin, a set reached two ways listed once with both.EffectiveAccess—{ userId: string; organizationId: string | null; positions: string[]; permissionSets: EffectivePermissionSet[] }(sets in resolution order; organization = the caller's active one, vetted for the described user asexplainvets it).ISecurityService.describeEffectiveAccess?(userId: string, callerContext?: SecurityContext): Promise<EffectiveAccess>afterdescribeDelegableScope, docblock citing ADR-0090 D6/D12: resolved by the resolver enforcement uses; gated asexplainis (manage_users, org admin of an org the user belongs to, or a delegatedadminScopecovering the user); an unknown user refused exactly as one the caller may not manage; OPTIONAL with absence a defined state (REST door answers 501).
The full drafted text, measured on main df22adc3, is the #31215 dev report (also carried in the seat order). Optional member, so REQUIRED_MEMBERS in security-service.test.ts does not move.
Done when
- The three types are exported from
@objectstack/spec(api-surface regenerated) and the member is declared optional. - A test pins the member optional and the three types' shapes (type-level), beside the
describeDelegableScope?pins. - Changeset
'@objectstack/spec': minor.Clause-②: yes (widening),Metadata-protocol: none. - No plugin, REST or client change here: those land on security: a per-user effective-access read that says where each permission set comes from (default binding, position, direct) #31215, which is
Blocked-bythis card.
Related: #31215, ADR-0090, ADR-0131. Name precedent: DelegableScope / describeDelegableScope?; the maintainer's veto window on the names applies.
Activity
objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Claim: PM loop round 1 · spec half of #31215, filed by this seat at
domain:server#5's request (route-A decision 6711854159)Session:
session_01FEkQ5mw7HFYn9o4LEGMQdK(card threadsession_01FEkQ5odNVgHTd2MQbQCp5t, reused from #31169 after PR #31210 merged)Account:
os-project-managerBranch:
claude/project-thread-9crw47(the card thread's harness branch, restarted from currentorigin/main; a thread can push only its assigned branch)Worktree: the card thread's own checkout of
claude/project-thread-9crw47Domain:
domain:specSeat:
domain:spec#1File surface:
packages/spec/src/contracts/security-service.ts(three exported types besideDelegableScope, one optional member afterdescribeDelegableScope?), its test(s) underpackages/spec/src/contracts/, the spec artifacts its gates regenerate (api-surface and kin), root.changeset/. ⛔ plugin-security, rest, client, core (those are #31215's), ⛔ui/**.Container & model:
M,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; Clause-② widening → CONTRACT_REVIEW_TIER review by this seat before enqueue),effort: defaultClause-②: yes
Metadata-protocol: none
Responsibility:
objectstack: an optional ISecurityService member and its answer types, declared before any implementer exists | none | an administrator reading another user's effective permission sets and their originsThread-read: 6711854159
Premise: holds — the dev report on #31215 measured on
origin/maindf22adc3thatsecurity-service.tsdeclares no effective-access member; no open PR touchessecurity-service.tsatorigin/main733efbd4(all open PRs' file lists read).Serial constraints cleared: none — no open PR touches the file surface; #31215 is serial behind this card (Blocked-by #31238) and does NOT close with it.
Shape: route A per 6711854159; text drafted in the #31215 dev report (seat order
/mnt/project-files/pm-orders/spec/order-31238.md). Name precedentDelegableScope/describeDelegableScope?; the maintainer's veto window on the names applies.objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5odNVgHTd2MQbQCp5t
os-dev-report
{
"issue": 31238,
"status": "done",
"branch": "claude/project-thread-9crw47",
"pr": "#31256",
"session": "session_01FEkQ5odNVgHTd2MQbQCp5t",
"premise_still_valid": true,
"summary": "Draft PR #31256 (head 80410d2, branch restarted from origin/main 733efbd after #31210 merged; body 'Fixes #31238', never #31215). security-service.ts gains EffectivePermissionSetOrigin, EffectivePermissionSet, EffectiveAccess beside DelegableScope/PositionGrantSummary (TS, no Zod) and optional describeEffectiveAccess?(userId, callerContext?) after describeDelegableScope, docblocks as drafted in pm-orders/server/31215-spec-addition.md; the three explain gate arms re-read in explainAccessForCaller on 733efbd and hold. Changes against the order, each named in the PR body: (1) changeset graded patch, not minor: AGENTS.md Post-Task Checklist 3 and check-changeset-no-major grade Metadata-protocol none at patch, and the gate refused minor with this body (reproduced with a pull_request event); (2) the order's precedent 'describeDelegableScope?' is REQUIRED on main (REQUIRED_MEMBERS lists it), so the optional-member pins sit beside the reopenAudienceBindingSuggestion?/checkControlledByParentWrite? pins; (3) the absence paragraph adds 'callers feature-detect ... never an empty list' (reopen precedent wording). Clause-②: yes (widening) per the order (the claim line reads 'yes' with no arm). api-surface and export-origins regenerated: +3 names each.",
"tests": "security-service.test.ts: 2 new cases (optional member: absent stub satisfies the contract, unguarded call and RequiredMember listing are @ts-expect-error, present stub resolves; shapes: closed origins, position needs its name, toEqualTypeOf on the two interfaces and the member signature, exhaustive switch with never). vitest security-service.test.ts 29/29. Full spec suite under os-verify-lock on 80410d2: VERDICT command-exit 0, 821 files, 25966 passed, 1 todo. spec typecheck exit 0 incl. check:test-typecheck. Reverse check: member made required (sed, injected=1 removed=0 by grep count) -> check:test-typecheck exit 1, 4 type errors in security-service.test.ts; restored with git checkout HEAD, git diff HEAD empty, blob hash equal to HEAD. Deviation: the mutation used sed with grep-count proof instead of scripts/ablation-replace.mjs; no dist/build involved (type-level only).",
"gates": "objectstack-ai/objectstack 80410d2: dispatch-gates --commands 82 derived (5 paths); 81 exit 0, 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (needs every package's dist; CI's). --ran: 82 accounted, 81 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. check:generated: api-surface + export-origins stale, --fix regenerated, then green. check-changeset-no-major with GITHUB_EVENT_NAME=pull_request and this PR body: exit 0 (LEVEL AXIS ok). ui grep for the three names: 0 hits (no check:spec-symbols collision). CI check-runs: not yet started/in_progress at report time; not waited. Full list: project file pm-orders/spec/31238-gates-ran.txt.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4 — reads only: issue_read get #31238, issue_read get_comments #31215, issue_read get_comments #31238 x2; no MCP write",
"api_writes": "2 — relay pr_create (fleet-write run 42409116098, PR #31256, 6908 bytes sent = stored, no assignees, no labels); this os-dev-report comment via post-stamped. Plus 4 git pushes of the harness branch (not REST).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: #31215 · the unknown-user answer differs from explain's (explain answers an admitted caller 404 for an id with no sys_user row; this contract says refused exactly as not-yours); #31215 names it in its PR, as seat decision 6711854159 requires."
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:spec#1 · os-project-manager · session_01FEkQ5mw7HFYn9o4LEGMQdK
Claim amendment · 2026-11-07T20:16Z · to claim 6711887108 (same session, branch
claude/project-thread-9crw47).File surface: adds
packages/plugins/plugin-security/src/registered-security-service-members.pin.test.tsonly — the pin that enumeratesISecurityServicemembers turnedType Check · workspacered on80410d2f(check:test-typecheck, 1 type error in that file) when the contract gaineddescribeEffectiveAccess?. The pin moves with the contract; ⛔ every other plugin-security file stays #31215's.Fix round for contract review 6712477832 (FAIL, M1 + S1–S3): the seat rules M1 as a fourth origin kind for resolver-derived standing (
kind: 'derived'with a closedsourceunion measured over every resolver path that confers a set without a grant row or a position), keeping "matches enforcement by construction".