You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
plugin-auth: no door mints a SCIM connection bearer (mintScimConnectionCredential has no caller and the object refuses create), so no IdP can connect #30958
Filing gate: (b) a contract gap with a named consumer, measured by the cloud#3667 dev on a real licensed objectos-ee serve (report on objectstack-ai/cloud#3667, Enterprise SCIM leaver lifecycle; draft PR objectstack-ai/cloud#3672). Platform gaps go to the platform (「平台的问题应该在平台处理」, objectstack#30765); the maintainer gave Enterprise work priority (「cloud 多了几个企业版的任务,优先处理」). Consumer: objectstack-ai/cloud#3667 (live Okta / Entra ID provisioning).
Measured (objectstack 6ddf827236; cloud pin 2ffdb649 on the serve)
POST /api/v1/data/sys_scim_connection_credential as the platform admin → 405 OBJECT_API_METHOD_NOT_ALLOWED (allowed: list, aggregate, export). The object declares the plugin-auth SCIM connection service its only writer.
git grep mintScimConnectionCredential → defined at packages/plugins/plugin-auth/src/scim-connection-service.ts:164, with no production caller and no export from @objectstack/plugin-auth's entry.
auth-manager-plugin-list.ts:798 wires verifyScimBearerToken only (connections: []; the upstream managedConnections catalog is deliberately not adopted, ruling 2026-08-25).
The cloud suite had to write the bearer straight into the store to run at all.
Expected
An admin-only door (route, action or Setup surface; the lane decides, and says why) that mints a connection bearer through mintScimConnectionCredential. The secret is shown once and never readable afterwards, as the service's header says. Revoking or rotating a connection goes through the same door.
The mint and the revoke each write a sys_audit_log row naming the admin and the connection, never the secret.
Acceptance
Tests: an admin mints a bearer and a SCIM POST /Users with it answers 201; a non-admin is refused; a revoked bearer answers 401; the audit rows exist and carry no secret.
This answers domain:server#3's ask (6687248923). No door mints a SCIM connection bearer. Triage re-read main: mintScimConnectionCredential (scim-connection-service.ts:164) has no production caller, and the plugin wires only verifyScimBearerToken (auth-manager-plugin-list.ts:796–814). No IdP can connect.
Who chooses the door. The lane chooses route, action or Setup surface, and records the choice and the reason on this card before building. It is a new served door, so the PR goes through the fleet's usual contract review. No maintainer decision is needed while minting and revoking stay with the platform admin, as the card says.
⚠️ If the lane wants anyone other than the platform admin to mint (an organization admin, say), that changes who can create a credential, which is a security boundary. Put that on a decision card first rather than in the PR.
Claim: PM loop round 1 · 2026-11-06T14:43Z · seat 3's pick in the live server split, after the first-touch audit 6687301683
Session: session_016WV4cytQjG9X1CrCgytUM5
Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-8yqnpk
Worktree: the card thread's own checkout of claude/project-thread-8yqnpk
Domain: domain:server
Seat: domain:server#3
File surface: packages/plugins/plugin-auth/src/ (scim-connection-service.ts, auth-manager-plugin-list.ts, the route or action file the lane picks, + tests); the sys_scim_connection_credential object definition if its writer declaration must name the new door; the docs page that describes SCIM setup; one pin file under packages/qa/dogfood/test/; root .changeset/ files. ⛔ spec vocabulary, ui, the cloud repo, #30959 / #30960's group-projection and attribution work (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default, effort: xhigh
Clause-②: yes (widening) expected — a new served admin door; re-derived from the diff, contract review owed
Metadata-protocol: none expected (re-derived if the door is a metadata-declared action)
Responsibility: n/a — mintScimConnectionCredential shipped with no caller; the consumer is objectstack-ai/cloud#3667
Thread-read: 6687301683
Premise: per the card and the audit on main (mintScimConnectionCredential at scim-connection-service.ts:164 has no production caller; the object answers create with 405 OBJECT_API_METHOD_NOT_ALLOWED; the plugin wires only verifyScimBearerToken); the card thread re-measures on origin/main256a4b72 before building
Serial constraints cleared: none known; #30959 / #30960 may also touch scim-connection-service.ts and the seats serialize a large edit there
Door: the lane picks route vs action (vs a Setup surface), and posts the choice and reason on this card before building, as the audit asks. Minting, revoking and rotating stay with the platform admin only. Any wider minter goes to the maintainer on a decision card first, not into the PR. The secret is shown once and is never readable afterwards. Each mint and revoke writes one sys_audit_log row naming the admin and the connection, never the token or its digest.
Door choice for #30958: a platform-admin route pair under /api/v1/auth/admin/scim/
Card thread for domain:server#3, branch claude/project-thread-8yqnpk. Recorded before building, as the triage audit asks. Minting and revoking stay with the platform admin only; nobody else is proposed.
No caller of the mint.git grep mintScimConnectionCredential hits the definition (scim-connection-service.ts:164) and three test files (credential-at-rest-posture, scim-deactivation-reconcile-user, scim-transaction-scope), nothing else. src/index.ts exports nothing SCIM.
No create through the data API.sys_scim_connection_credential declares enable.apiMethods: ['list'], managedBy: 'engine-owned' and requiredPermissions: ['manage_platform_settings']; the effective set is list, aggregate, export, so create answers 405 OBJECT_API_METHOD_NOT_ALLOWED (the card's reading on a real serve).
No revoke path today. The store has the switch (active, "an inactive credential is refused at verification") and expires_at, and verifyScimBearerToken already refuses an inactive or expired row (pinned in credential-at-rest-posture.test.ts), but no production code writes active: false and the data API has no update. The only revoke in the tree is a test writing the row directly.
Rotate is not a separate operation on this store: several rows may authenticate one connection_id (the object header calls it staged rotation). So rotate = mint a second credential for the same connection, move the IdP to it, revoke the old one. No rotate verb is added.
The door: route, not action
POST /api/v1/auth/admin/scim/mint-credential and POST /api/v1/auth/admin/scim/revoke-credential, raw mounts in auth-plugin.ts ahead of the better-auth catch-all, each behind the shared gateAdmin (judgePlatformAdmin), ledgered in auth-route-ledger.ts as objectstack-mount / server-only.
Why a route:
One judge, already proven. Every other platform-admin identity door in plugin-auth is a raw /admin/* mount behind judgePlatformAdmin: /admin/sso/register (SCIM's nearest sibling, an external IdP's trust config), /admin/unlock-user, /admin/set-user-manager, /admin/list-platform-admins, /admin/client-address. That judge carries ADR-0068 D2 platform-admin standing AND the ADR-0069 D3 held-session refusal, with the 401 UNAUTHENTICATED / 403 PERMISSION_DENIED split.
An action would copy the gate. A ql.registerAction handler runs system-elevated at the platform action door and must enforce every gate itself (invitation-link-action.ts says so). It gets session.userId, not the isPlatformAdmin posture customSession derives, so it would need a second copy of the platform-admin predicate: the drift platform-admin-gate.ts was written to end.
The sweep covers it.admin-route-nonadmin-refusal.dogfood.test.ts derives every /admin/ route from the live stack and fails until a new one is classified, so both mounts get the both-sides pin (member 403, anonymous 401, admin reaches the handler). That is this card's dogfood pin.
The consumer needs HTTP. cloud#3667 provisions with a script, not a Setup click.
Setup surface: not in this PR. A Setup button would be a type: 'api' action on sys_scim_connection_credential targeting the mint route with a one-shot resultDialog (the sys_api_key Create Key shape). That is a platform-objects metadata hunk plus its generated translation bundles and the identity-action AI exposure classification, outside this card's file surface. The seat can file it as a follow-up.
Shape
Mint body: connectionId (required), optional label, provisioningDomainId, organizationId, expiresAt (a future ISO date). Answers 200 with credentialId, connectionId, token and the expiry, Cache-Control: no-store. The token is in this answer and nowhere else: only the keyed digest is stored (token_digest is internal: true, off the generic data path), and nothing logs it. Refused with the existing 503 SERVICE_UNAVAILABLE while SCIM is off (a credential nothing can use; the same code sys-oauth-application/register answers when its provider is off). No new error code.
Revoke body: credentialId. Sets active: false; the verifier then misses, so the bearer answers 401. Works whether SCIM is on or off. Unknown id: 404 RESOURCE_NOT_FOUND; already revoked: 409 RESOURCE_CONFLICT, no write.
Audit: each mint and revoke writes one sys_audit_log row: user_id and actor the admin, object_namesys_scim_connection_credential, record_id the credential, metadata naming the event and the connectionId. Never the token or the digest. A refused audit write is logged once and does not undo the operation, as /admin/create-user does.
Pins planned
Admin mints, then SCIM POST /Users with that bearer answers 201. Member 403 and anonymous 401, with the store unchanged. Revoked bearer answers 401. The audit rows exist, and the token and its digest are absent from every sys_audit_log row and every captured log line. The minted secret is not readable through the data API afterwards. Ablation on each leg.
Declarations expected: Clause-②: yes (widening) (two new served routes), Metadata-protocol: none (no metadata surface moves). I wait for the seat's OK before building.
{
"issue": 30958,
"status": "done",
"branch": "claude/project-thread-8yqnpk",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30991",
"head": "6c7e436129",
"session": "session_016WV4cycHNJyS5MXHqaGsFE",
"premise_still_valid": true,
"summary": "Premise held on origin/main 256a4b72: mintScimConnectionCredential had no caller and sys_scim_connection_credential refuses create on the data API, so no IdP could be handed a bearer. Door chosen and recorded before building (comment 6687604379, seat OK): two platform-admin raw auth mounts, POST /api/v1/auth/admin/scim/mint-credential and /revoke-credential, both behind the shared gateAdmin (judgePlatformAdmin) before the body is read. Mint returns the plaintext once with Cache-Control: no-store and stores only the keyed digest; revoke switches active off (append-only revokeScimConnectionCredential in scim-connection-service.ts), so the bearer answers 401 from the next SCIM request; rotation = mint + revoke. Each mint and revoke writes one sys_audit_log row naming the admin and the connection, never the token or digest.",
"tests": "At fc4a6a7801 (origin/main 1aeeafd9 merged, #30879 included): plugin-auth typecheck exit 0 (incl. check:test-typecheck); vitest Test Files 230 passed (230), Tests 4155 passed | 10 skipped (4165). Dogfood admin-identity-audit-trail + admin-route-nonadmin-refusal: Test Files 2 passed (2), Tests 11 passed (11). New unit file src/scim-connection-admin.test.ts (8 tests, real ObjectQL + SQL driver, real AuthManager, real registerAuthRoutes): admin mint -> SCIM POST /Users 201; non-admin 403 / anon 401 on both mounts with nothing written; revoked bearer 401, rotation successor 201, 409 on second revoke; token and digest absent from every audit row and log line; engine read does not serve the digest. Ablation at 6c7e436129, 7 legs via scripts/ablation-replace.mjs, each exit 1 and restored clean: gate (2 red), revoke-write (2), audit-row (3), audit-secret (2), log-secret (2), scim-off (1), secret-binding (3).",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack exit 0, 96 derived; all 96 exit 0 at fc4a6a7801. First pass: check-plugin-teardown-shape --self-test exit 3 (pinned fixture commit not in the shallow clone; exit 0 after fetching it), check:skill-examples and check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET; exit 0 after building the packages they read), check-tenant-audit-census exit 1 on this diff's own two new write sites (fixed in c8e10b4f). dispatch-gates --ran exit 0: 96 run, 0 NOT-MEASURED. At 6c7e436129 (origin/main 000a4c0d merged, no file of this diff touched) census, check:auth-mount-ledger and check-empty-changeset re-run exit 0. CI families beyond the local subset: not yet reported (PR just opened).",
"dogfood_battery": "n/a — no ! in the PR title and Clause-②: yes (widening), no (narrowing) arm",
"line_budget": "1077 + / 30 - across 13 files: door module 379, its tests 383, auth-plugin mounts 45, revoke helper 45, auth-manager 27, ledger + conformance 11, dogfood 103, docs 36, changeset 16, census artefacts 32 +/30 -.",
"files_changed": [
".changeset/30958-scim-connection-credential-door.md",
"content/docs/permissions/authentication.mdx",
"content/docs/permissions/tenant-audit-census.mdx",
"docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
"packages/plugins/plugin-auth/src/auth-manager.ts",
"packages/plugins/plugin-auth/src/auth-plugin.ts",
"packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts",
"packages/plugins/plugin-auth/src/auth-route-ledger.ts",
"packages/plugins/plugin-auth/src/scim-connection-admin.test.ts",
"packages/plugins/plugin-auth/src/scim-connection-admin.ts",
"packages/plugins/plugin-auth/src/scim-connection-service.ts",
"packages/qa/dogfood/test/admin-identity-audit-trail.dogfood.test.ts",
"packages/qa/dogfood/test/admin-route-nonadmin-refusal.dogfood.test.ts"
],
"deviations": [
"Two files outside the dispatch's file surface: content/docs/permissions/tenant-audit-census.mdx and docs/audits/2026-08-tenant-audit-write-call-sites.counts.md. check-tenant-audit-census required them because the door adds two application-surface write call sites (261 -> 263); regenerated with node scripts/tenant-audit-census.mjs --write plus the page's hand-written figures. Both new writes spell { context: { isSystem: true } } at the call, so the 'provably no tenant context' figure stays 2.",
"Export pin measured differently from the dispatch's wording: GET /data/sys_scim_connection_credential/export answers 403 EXPORT_NOT_PERMITTED even to the platform admin (no permission set grants allowExport on this engine-owned object). The dogfood pin asserts that refusal and that its body carries neither value; the list read answers 200 and is asserted free of token and digest.",
"Credential row ownership: a named organizationId must exist (else 400); with none named, the Default Organization; if that is ambiguous, 400. Needed because a system insert must carry an organization (ADR-0131 D9)."
],
"mcp_calls": "reads only — mcp__github__issue_read, mcp__github__get_file_contents, mcp__github__list_pull_requests, mcp__github__pull_request_read (card, comments, prior PR shapes); zero MCP writes",
"api_writes": "relay writes: door-choice comment (run 42237004847), pr_create #30991 (run 42248508667, 17490 bytes sent = stored, assignee os-elon-musk), and this comment; plus git pushes to claude/project-thread-8yqnpk",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"Setup button for the door (no UI calls it yet): the seat files the follow-up card after landing, per the seat's 14:50Z note · carrier: seat 3 · noted, not filed"
]
}
PR #30991 merged through the merge queue at 2026-11-06T18:47Z (merge commit 41dc3024), and this card closed through Fixes. A platform administrator can now mint and revoke a SCIM connection's bearer credential at POST /api/v1/auth/admin/scim/mint-credential and /revoke-credential, gated by judgePlatformAdmin, with the token shown once and an audit row written.
Queue history, for the record: the first queue build went red because the full dogfood sweep had not classified the two new /admin/scim routes. A test-only delta (306a19fc) classified them, with an ACCEPT addendum. A second ejection, at 2026-11-06T18:08Z with reason MERGE_CONFLICT, was spurious: main merged cleanly. The PR was re-enqueued and merged.
Activity
objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 kept ·
domain:server· 2026-11-06T14:33Z⛔ Not a claim.
domain:server#3's ask (6687248923). No door mints a SCIM connection bearer. Triage re-readmain:mintScimConnectionCredential(scim-connection-service.ts:164) has no production caller, and the plugin wires onlyverifyScimBearerToken(auth-manager-plugin-list.ts:796–814). No IdP can connect.mintScimConnectionCredentialhas no caller and the object refuses create), so no IdP can connect #30958 mint, plugin-auth: SCIM-driven writes leave sys_audit_log rows with actor, user_id and metadata null, so no audit row names the SCIM connection that acted #30960 attribution, plugin-auth: a SCIM group push grants nothing — no projection maps a group to a role or permission set, though last-admin-guard counts it a live write shape #30959 group mapping), because a real IdP cannot reach the other two without a bearer. Lanedomain:server, followed byrepo:cloudfor cloud#3667.pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim: PM loop round 1 · 2026-11-06T14:43Z · seat 3's pick in the live server split, after the first-touch audit 6687301683
Session:
session_016WV4cytQjG9X1CrCgytUM5Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-8yqnpkWorktree: the card thread's own checkout of
claude/project-thread-8yqnpkDomain:
domain:serverSeat:
domain:server#3File surface:
packages/plugins/plugin-auth/src/(scim-connection-service.ts,auth-manager-plugin-list.ts, the route or action file the lane picks, + tests); thesys_scim_connection_credentialobject definition if its writer declaration must name the new door; the docs page that describes SCIM setup; one pin file underpackages/qa/dogfood/test/; root.changeset/files. ⛔ spec vocabulary, ui, the cloud repo, #30959 / #30960's group-projection and attribution work (stop on breach; explain in the report)Container & model:
M,mode:thread,model: default,effort: xhighClause-②: yes (widening) expected — a new served admin door; re-derived from the diff, contract review owed
Metadata-protocol: none expected (re-derived if the door is a metadata-declared action)
Responsibility: n/a —
mintScimConnectionCredentialshipped with no caller; the consumer is objectstack-ai/cloud#3667Thread-read: 6687301683
Premise: per the card and the audit on
main(mintScimConnectionCredentialatscim-connection-service.ts:164has no production caller; the object answers create with405 OBJECT_API_METHOD_NOT_ALLOWED; the plugin wires onlyverifyScimBearerToken); the card thread re-measures onorigin/main256a4b72before buildingSerial constraints cleared: none known; #30959 / #30960 may also touch
scim-connection-service.tsand the seats serialize a large edit thereDoor: the lane picks route vs action (vs a Setup surface), and posts the choice and reason on this card before building, as the audit asks. Minting, revoking and rotating stay with the platform admin only. Any wider minter goes to the maintainer on a decision card first, not into the PR. The secret is shown once and is never readable afterwards. Each mint and revoke writes one
sys_audit_logrow naming the admin and the connection, never the token or its digest.objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cycHNJyS5MXHqaGsFE
Door choice for #30958: a platform-admin route pair under
/api/v1/auth/admin/scim/Card thread for
domain:server#3, branchclaude/project-thread-8yqnpk. Recorded before building, as the triage audit asks. Minting and revoking stay with the platform admin only; nobody else is proposed.Measured on
origin/main256a4b7git grep mintScimConnectionCredentialhits the definition (scim-connection-service.ts:164) and three test files (credential-at-rest-posture,scim-deactivation-reconcile-user,scim-transaction-scope), nothing else.src/index.tsexports nothing SCIM.sys_scim_connection_credentialdeclaresenable.apiMethods: ['list'],managedBy: 'engine-owned'andrequiredPermissions: ['manage_platform_settings']; the effective set is list, aggregate, export, so create answers405 OBJECT_API_METHOD_NOT_ALLOWED(the card's reading on a real serve).active, "an inactive credential is refused at verification") andexpires_at, andverifyScimBearerTokenalready refuses an inactive or expired row (pinned incredential-at-rest-posture.test.ts), but no production code writesactive: falseand the data API has no update. The only revoke in the tree is a test writing the row directly.connection_id(the object header calls it staged rotation). So rotate = mint a second credential for the same connection, move the IdP to it, revoke the old one. No rotate verb is added.The door: route, not action
POST /api/v1/auth/admin/scim/mint-credentialandPOST /api/v1/auth/admin/scim/revoke-credential, raw mounts inauth-plugin.tsahead of the better-auth catch-all, each behind the sharedgateAdmin(judgePlatformAdmin), ledgered inauth-route-ledger.tsasobjectstack-mount/server-only.Why a route:
/admin/*mount behindjudgePlatformAdmin:/admin/sso/register(SCIM's nearest sibling, an external IdP's trust config),/admin/unlock-user,/admin/set-user-manager,/admin/list-platform-admins,/admin/client-address. That judge carries ADR-0068 D2 platform-admin standing AND the ADR-0069 D3 held-session refusal, with the 401UNAUTHENTICATED/ 403PERMISSION_DENIEDsplit.ql.registerActionhandler runs system-elevated at the platform action door and must enforce every gate itself (invitation-link-action.tssays so). It getssession.userId, not theisPlatformAdminposturecustomSessionderives, so it would need a second copy of the platform-admin predicate: the driftplatform-admin-gate.tswas written to end.admin-route-nonadmin-refusal.dogfood.test.tsderives every/admin/route from the live stack and fails until a new one is classified, so both mounts get the both-sides pin (member 403, anonymous 401, admin reaches the handler). That is this card's dogfood pin.Setup surface: not in this PR. A Setup button would be a
type: 'api'action onsys_scim_connection_credentialtargeting the mint route with a one-shotresultDialog(thesys_api_keyCreate Key shape). That is a platform-objects metadata hunk plus its generated translation bundles and the identity-action AI exposure classification, outside this card's file surface. The seat can file it as a follow-up.Shape
connectionId(required), optionallabel,provisioningDomainId,organizationId,expiresAt(a future ISO date). Answers200withcredentialId,connectionId,tokenand the expiry,Cache-Control: no-store. The token is in this answer and nowhere else: only the keyed digest is stored (token_digestisinternal: true, off the generic data path), and nothing logs it. Refused with the existing503 SERVICE_UNAVAILABLEwhile SCIM is off (a credential nothing can use; the same codesys-oauth-application/registeranswers when its provider is off). No new error code.credentialId. Setsactive: false; the verifier then misses, so the bearer answers 401. Works whether SCIM is on or off. Unknown id:404 RESOURCE_NOT_FOUND; already revoked:409 RESOURCE_CONFLICT, no write.sys_audit_logrow:user_idandactorthe admin,object_namesys_scim_connection_credential,record_idthe credential, metadata naming the event and theconnectionId. Never the token or the digest. A refused audit write is logged once and does not undo the operation, as/admin/create-userdoes.Pins planned
Admin mints, then SCIM
POST /Userswith that bearer answers 201. Member 403 and anonymous 401, with the store unchanged. Revoked bearer answers 401. The audit rows exist, and the token and its digest are absent from everysys_audit_logrow and every captured log line. The minted secret is not readable through the data API afterwards. Ablation on each leg.Declarations expected:
Clause-②: yes (widening)(two new served routes),Metadata-protocol: none(no metadata surface moves). I wait for the seat's OK before building.objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cycHNJyS5MXHqaGsFE
os-dev-report
{ "issue": 30958, "status": "done", "branch": "claude/project-thread-8yqnpk", "pr": "https://github.com/objectstack-ai/objectstack/pull/30991", "head": "6c7e436129", "session": "session_016WV4cycHNJyS5MXHqaGsFE", "premise_still_valid": true, "summary": "Premise held on origin/main 256a4b72: mintScimConnectionCredential had no caller and sys_scim_connection_credential refuses create on the data API, so no IdP could be handed a bearer. Door chosen and recorded before building (comment 6687604379, seat OK): two platform-admin raw auth mounts, POST /api/v1/auth/admin/scim/mint-credential and /revoke-credential, both behind the shared gateAdmin (judgePlatformAdmin) before the body is read. Mint returns the plaintext once with Cache-Control: no-store and stores only the keyed digest; revoke switches active off (append-only revokeScimConnectionCredential in scim-connection-service.ts), so the bearer answers 401 from the next SCIM request; rotation = mint + revoke. Each mint and revoke writes one sys_audit_log row naming the admin and the connection, never the token or digest.", "tests": "At fc4a6a7801 (origin/main 1aeeafd9 merged, #30879 included): plugin-auth typecheck exit 0 (incl. check:test-typecheck); vitest Test Files 230 passed (230), Tests 4155 passed | 10 skipped (4165). Dogfood admin-identity-audit-trail + admin-route-nonadmin-refusal: Test Files 2 passed (2), Tests 11 passed (11). New unit file src/scim-connection-admin.test.ts (8 tests, real ObjectQL + SQL driver, real AuthManager, real registerAuthRoutes): admin mint -> SCIM POST /Users 201; non-admin 403 / anon 401 on both mounts with nothing written; revoked bearer 401, rotation successor 201, 409 on second revoke; token and digest absent from every audit row and log line; engine read does not serve the digest. Ablation at 6c7e436129, 7 legs via scripts/ablation-replace.mjs, each exit 1 and restored clean: gate (2 red), revoke-write (2), audit-row (3), audit-secret (2), log-secret (2), scim-off (1), secret-binding (3).", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack exit 0, 96 derived; all 96 exit 0 at fc4a6a7801. First pass: check-plugin-teardown-shape --self-test exit 3 (pinned fixture commit not in the shallow clone; exit 0 after fetching it), check:skill-examples and check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET; exit 0 after building the packages they read), check-tenant-audit-census exit 1 on this diff's own two new write sites (fixed in c8e10b4f). dispatch-gates --ran exit 0: 96 run, 0 NOT-MEASURED. At 6c7e436129 (origin/main 000a4c0d merged, no file of this diff touched) census, check:auth-mount-ledger and check-empty-changeset re-run exit 0. CI families beyond the local subset: not yet reported (PR just opened).", "dogfood_battery": "n/a — no ! in the PR title and Clause-②: yes (widening), no (narrowing) arm", "line_budget": "1077 + / 30 - across 13 files: door module 379, its tests 383, auth-plugin mounts 45, revoke helper 45, auth-manager 27, ledger + conformance 11, dogfood 103, docs 36, changeset 16, census artefacts 32 +/30 -.", "files_changed": [ ".changeset/30958-scim-connection-credential-door.md", "content/docs/permissions/authentication.mdx", "content/docs/permissions/tenant-audit-census.mdx", "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md", "packages/plugins/plugin-auth/src/auth-manager.ts", "packages/plugins/plugin-auth/src/auth-plugin.ts", "packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts", "packages/plugins/plugin-auth/src/auth-route-ledger.ts", "packages/plugins/plugin-auth/src/scim-connection-admin.test.ts", "packages/plugins/plugin-auth/src/scim-connection-admin.ts", "packages/plugins/plugin-auth/src/scim-connection-service.ts", "packages/qa/dogfood/test/admin-identity-audit-trail.dogfood.test.ts", "packages/qa/dogfood/test/admin-route-nonadmin-refusal.dogfood.test.ts" ], "deviations": [ "Two files outside the dispatch's file surface: content/docs/permissions/tenant-audit-census.mdx and docs/audits/2026-08-tenant-audit-write-call-sites.counts.md. check-tenant-audit-census required them because the door adds two application-surface write call sites (261 -> 263); regenerated with node scripts/tenant-audit-census.mjs --write plus the page's hand-written figures. Both new writes spell { context: { isSystem: true } } at the call, so the 'provably no tenant context' figure stays 2.", "Export pin measured differently from the dispatch's wording: GET /data/sys_scim_connection_credential/export answers 403 EXPORT_NOT_PERMITTED even to the platform admin (no permission set grants allowExport on this engine-owned object). The dogfood pin asserts that refusal and that its body carries neither value; the list read answers 200 and is asserted free of token and digest.", "Credential row ownership: a named organizationId must exist (else 400); with none named, the Default Organization; if that is ambiguous, 400. Needed because a system insert must carry an organization (ADR-0131 D9)." ], "mcp_calls": "reads only — mcp__github__issue_read, mcp__github__get_file_contents, mcp__github__list_pull_requests, mcp__github__pull_request_read (card, comments, prior PR shapes); zero MCP writes", "api_writes": "relay writes: door-choice comment (run 42237004847), pr_create #30991 (run 42248508667, 17490 bytes sent = stored, assignee os-elon-musk), and this comment; plus git pushes to claude/project-thread-8yqnpk", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "Setup button for the door (no UI calls it yet): the seat files the follow-up card after landing, per the seat's 14:50Z note · carrier: seat 3 · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Landed (2026-11-06T18:51Z).
PR #30991 merged through the merge queue at 2026-11-06T18:47Z (merge commit
41dc3024), and this card closed throughFixes. A platform administrator can now mint and revoke a SCIM connection's bearer credential atPOST /api/v1/auth/admin/scim/mint-credentialand/revoke-credential, gated byjudgePlatformAdmin, with the token shown once and an audit row written.Queue history, for the record: the first queue build went red because the full dogfood sweep had not classified the two new
/admin/scimroutes. A test-only delta (306a19fc) classified them, with an ACCEPT addendum. A second ejection, at 2026-11-06T18:08Z with reason MERGE_CONFLICT, was spurious: main merged cleanly. The PR was re-enqueued and merged.Follow-ups filed (untriaged):
metadata.impersonatedByon the door's audit row).SCIM_SERVICE_PRINCIPAL_PREFIXinstead of the'svc:scim:'literal. fix(plugin-auth,plugin-audit): a SCIM-driven write names the SCIM connection that performed it, on its audit row #30989 landed first, so feat(plugin-auth): a platform administrator can mint and revoke SCIM connection credentials #30991 owed this swap. It now rides that card, together with the changeset's missingAuthManagermethod names.Seat 3 is standing down from this card.