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: pending, SSO-only users on a managed environment — add and CSV import with position, permission sets and manager, refused by every password door, with a host seam on create, deactivate and reactivate #33181
Work (objectstack-ai/cloud#4465, child 1a; execution terms "Environment")
Add a dedicated door that does not depend on the better-auth admin plugin. On Free and Team hosted kernels that plugin mounts only with SCIM (auth-manager-plugin-list.ts:211), and admin/import-users answers 501 there (auth-plugin.ts:4604).
The door accepts email, name, position, permission sets and manager; CSV import reports per-row results.
Give the pending marker its own value, never env_native: set-user-password admits env_native rows (admin-user-endpoints.ts:1120-1136). Every password door refuses the pending marker.
First platform-SSO sign-in binds to the pending row (implicit-account-linking.ts). Confirm by a run whether email_verified is needed; requireLocalEmailVerified is deprecated.
Add a host seam on create, deactivate and reactivate, so a host can forward an invitation or a removal. The cloud implements it (cloud card C4).
Reword the managed-mode 409 messages from objectstack#25083 ("Invite them from the organisation in the cloud console").
Measure first: does today's deactivation (admin/ban-user) answer on a Free hosted kernel? If not, add a deactivation door here.
Suggested priority:p1 (the maintainer: core onboarding flow). Routing: triage (domain:server).
priority:p1 on the maintainer's word, verbatim (seat session session_01Q4EjjPP1zuWBNq3nBXVei9, 2026-11-14): 「都是p1,车道自己认领就可以」. Triage routes it to its lane; the lane claims it.
Grade p1 on the maintainer's word, verbatim: 「都是p1,车道自己认领就可以」 (seat session session_01Q4EjjPP1zuWBNq3nBXVei9). This is a child of objectstack-ai/cloud#4465, which records rulings 1–10: people are added in the environment, and credentials stay in the cloud.
Claim: PM loop round 14, card thread · 2026-11-14T01:44Z · p1 on the maintainer's word 「都是p1,车道自己认领就可以」 (triage 6868743330)
Session: session_01L9qibvhGW6DCBPjrcAPjvh
Account: os-tesla
Branch: claude/project-thread-cl505i
Worktree: objectstack-issue-33181
Domain: domain:server
Seat: domain:server#7
File surface: packages/plugins/plugin-auth/src/ — a new pending-user door file, the password doors' refusal of the pending marker, implicit-account-linking.ts (the first-SSO bind), cloud-managed.ts (the managed-mode 409 wording), the plugin wiring and the host seam's type; packages/spec/src/ only if the shape note names it and the seat accepts it; their tests; the auth docs page that lists these doors; one root changeset. Every file is named in a shape note before code. Stop on breach.
Container & model: L, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: high
Clause-②: yes (widening) — a new door adds pending users; refusing the new pending marker at the password doors narrows nothing, since no row carries it on main; any existing door that newly refuses something is declared as a narrowing arm in the shape note
Metadata-protocol: none — unless the marker lands in a spec enum, which the shape note states before code
Responsibility: managed environments have no working add-person door on Free / Team kernels (plugin-auth: the better-auth admin plugin mounts only with SCIM, and admin/import-users answers 501), objectstack | the cloud adds people only through its own console | every managed-environment admin who needs a person to exist before their first sign-in, and the seeds and approval flows that point at them
Thread-read: 6868743330
Premise: re-measure — the card's line references (auth-manager-plugin-list.ts:211, auth-plugin.ts:4604, admin-user-endpoints.ts:1120-1136) and whether admin/ban-user answers on a Free hosted kernel are measured at origin/main first
Serial constraints cleared: NOT yet for code — security#2's PR #33177 (#32087 item 5) changes the same password doors; measurement and the shape note proceed now, code starts only after #33177 has merged, on top of it. The maintainer's rulings 1–10 on objectstack-ai/cloud#4465 are outside this session's reach and are being quoted onto this card; nothing is inferred from them meanwhile.
Claim amendment to this seat's claim 6869596244 on #33181 · 2026-11-14T01:52Z: the seat accepts the shape note out/33181-proposed-shape.md (measured at origin/main8835532), with these choices.
The file surface adds:
packages/platform-objects/src/identity/sys-user.object.ts: one new option idp_pending on the existing source select, plus its description. The pending marker has no other home.
the eleven translations/*.objects.generated.ts that check-i18n-bundles.mjs --write regenerates from it. They are regenerated, never hand-edited.
inside plugin-auth, the files the note names: pending-sso-users.ts (new), auth-plugin.ts, admin-user-endpoints.ts, auth-manager-before-hook.ts, sso-only-local-password.ts, auth-manager-database-hooks.ts, auth-manager.ts, auth-manager-plugin-list.ts / auth-schema-config.ts, cloud-managed.ts, index.ts, and the header of implicit-account-linking.ts;
content/docs/permissions/authentication.mdx.
The seat's choices:
The doors answer only on a cloud-managed environment, and elsewhere answer 409.
Metadata-protocol: none: a platform-object select option, not a spec enum.
A host failure leaves the operation standing. The answer reports it per row, and re-adding a pending person re-fires the seam.
Deactivation reuses the existing admin/ban-user / unban-user doors on kernels without the admin plugin, rather than adding a second vocabulary. That carries a declared narrowing arm, so the PR declares Clause-②: yes (widening, narrowing) with the BREAKING banner, and the contract review runs at CONTRACT_REVIEW_TIER.
Sessions on non-SSO channels are refused for a row still marked pending. This narrows nothing on main.
The exact sentences and any point the maintainer's rulings on objectstack-ai/cloud#4465 fix are taken from those rulings once they are quoted on this card.
Code still starts only after PR #33177 has merged.
Second claim amendment to this seat's claim 6869596244 on #33181 · 2026-11-14T02:54Z: the file surface adds, all in packages/plugins/plugin-auth/src/ unless named otherwise:
leaf modules pending-sso-marker.ts, environment-user-host.ts, user-session-admission.ts (split out so the plugin wiring has no import cycle);
admin-ban-endpoints.ts and user-ban-write.ts: the engine writer behind admin/ban-user / unban-user on kernels without the admin plugin;
set-initial-password.ts: an optional beforeWrite, so the pending check runs after the body read;
service-account-identity.ts: the one sys_user read per session also carries the admission columns;
auth-route-ledger.ts and its conformance list (the new routes);
auth-manager-plugin-list.ts and auth-schema-config.ts leave the surface; they are not touched.
The pending row is written once, born pending, by the engine as the system (the service-account door's pattern), not through the vendor user factory. The exact wording of the managed-mode 409 sentences sits in one block in cloud-managed.ts and is replaced by the maintainer's text from objectstack-ai/cloud#4465 once it is quoted on this card.
Ruling text relayed 2026-11-14T03:06Z, on the maintainer's request in seat session session_01Q4EjjPP1zuWBNq3nBXVei9: 「server agent 项目读不到 cloud 仓库,请把原文贴到两张卡上」. This card is child 1a of objectstack-ai/cloud#4465 (private repo). Below is the verbatim text of that card's body as last edited at 2026-11-14T03:05Z: the rulings that bear on child 1a (1–5, 9, 10), the environment-side execution terms, the edge paths, and the open facts that name child 1a. Rulings 6 (console invite door), 7 (ADR note) and 8 (direct redirect, carried by #33183) do not bear on this card and are left out. The cloud code paths cited below are in the cloud repo and are given as references, not as files in this repo.
Rulings (the maintainer, 2026-11-13), verbatim
The split. The production environment is the source of truth for the roster and authorization: people, positions, permission sets, managers, lifecycle. Credentials stay in the cloud: every person is their own cloud account (email verification, password, social login).
Who may add people. An environment administrator who may add users has the same authority as an organization administrator inviting from the console. No separate authorization model.
No daily cap on environment-originated invitations. The basics are kept: each invitation is attributed to the acting administrator, and it is auditable.
The invited person's organization role is the ordinary member. The console is not needed, but it is not blocked either. The account is the person's own and can, for example, create a new organization.
Deactivation. Deactivating a plain member in the environment also removes them from the cloud organization. Their environment row and all their history stay. Reactivation re-sends the invitation. Exception: an organization owner or admin cannot be removed from the environment side; that is done in the console.
Organization owners and admins are environment administrators, projected one way. The maintainer: 「云端的组织管理员应该就是环境的管理员才合理吧」.
The control plane sends the environment the organization's current owner and admin ids on every change and at kernel build.
The environment grants admin_full_access to each linked account, matched by cloud user id, on every entry path. The grant is owned by the Default Organization.
Demotion or removal withdraws only a grant the projection wrote; a grant an environment administrator made stands. Removal also revokes credentials through the existing fan-out.
Nothing flows up: an environment-only administrator stays an organization member, and no environment call writes an organization role.
An environment administrator cannot withdraw a projected grant. That is a role change in the console.
「打开」 enters a non-creator admin as themself. Fact: today every 「打开」 enters as the environment's creator (routes/environment-lifecycle/sso.ts:318-325, auth-proxy-plugin.ts:605-609), so a non-creator admin has no admin standing of their own on any path.
Hosted has no local break-glass admin. The maintainer chose 「A」.
No hosted environment sets a local password for anyone, and existing owner break-glass passwords are invalidated.
Emergency access is a platform-operator procedure, audited: the platform-admin disable_platform_sso / enable_platform_sso from cloud#3134, or a one-time recovery link.
Self-hosted deployments keep local admins.
This supersedes cloud#3132's "keep a break-glass local admin" for hosted.
Deferred by the maintainer: 「代理用户先不考虑」. Audited "log in as" is a later item only.
Execution terms for the environment (children 1a / 2b), verbatim
Environment (children 1a / 2b):
A platform-admin gate. The environment id comes from the kernel binding.
The actor's cloud id comes from the linked objectstack-cloud account, never from request input. An admin who entered through the owner handoff is attributed through the handoff's by (the handoff signs in as the creator; handoff-sign-out.ts:9-12, cloud#2506).
Hosted has no local admin (ruling 10). An admin's attribution comes from their own linked cloud account (ruling 9 makes 「打开」 enter as self).
A durable outbox with retry (mirror sys_environment_revocation), with per-row invitation status in Setup → Users.
Deleting or deactivating a pending row cancels its cloud invitation (the email-typo case).
An owner or admin 409 refuses the whole deactivation.
No database transaction is held across the invite call. The cap calls back into the environment (GET /_admin/environments/:id/ai-seats, which fails closed with 503).
The pending marker must not read as env_native: set-user-password admits env_native rows (admin-user-endpoints.ts:1120-1136), and a row with no sys_account reads env_native today. Every password door refuses the pending marker.
The pending-user door does not depend on the better-auth admin plugin. On Free and Team hosted kernels that plugin mounts only with SCIM (auth-manager-plugin-list.ts:211; admin/import-users answers 501 there, auth-plugin.ts:4604). Mounting it on hosted would also expose impersonate and ban, which needs its own ruling.
Edge paths the children must cover, verbatim
Console-side removal or role change of a person the environment lists as active: the environment row stays active but cannot sign in. The roster shows that state.
A person invited directly from the console has no pending row and arrives by JIT, as today.
Adding an email that already has an environment row: decide in child 1a whether that is a refusal or an update.
Reactivation, or a CSV row, at the developer cap is refused with 403 DEVELOPER_ORGANIZATION_MEMBER_LIMIT_REACHED. This is shown per row, and a CSV import reports partial failures row by row.
A pending row that never accepts: it stays pending, can be re-sent, and can be deleted, which cancels the invitation.
Open facts naming child 1a, verbatim
Does admin/ban-user (today's deactivation) answer on a Free hosted kernel? If not, child 1a needs its own deactivation door.
Rulings recorded after the body (comment 6870693029 on cloud#4465)
d-2 应急入口不考虑 d-3 同意
For this card: D-3 means stored local password hashes on hosted are refused, not deleted, so every password door refuses rather than clears. D-2 means no one-time recovery link is built; ruling 10's emergency access is not extended here.
{
"issue": 33181,
"status": "done",
"branch": "claude/project-thread-cl505i",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33227",
"head": "be43f4e1",
"session": "session_01L9qibvhGW6DCBPjrcAPjvh",
"premise_still_valid": true,
"summary": "Draft PR, one commit on origin/main 7257f57a. On a cloud-managed environment, POST /admin/add-sso-user and /admin/import-sso-users (platform-admin gated, no admin-plugin dependency, 409 RESOURCE_CONFLICT off managed) write a person born sys_user.source=idp_pending by one engine insert as the system, attributed to the administrator, with positions, permission sets (caller's context, one unit of work), membership and manager. Every password door (set-user-password, set-initial-password, reset-password, phone-number/reset-password) answers 409 for a pending row; session creation answers 403; the first platform-IdP sign-in binds (implicit-linking rule 2) and stampIdentitySource moves it to idp_provisioned. admin/ban-user and unban-user now work without the admin plugin (engine writer, session refusal with the vendor's 403 BANNED_USER). Host seam environmentUserHost: told after an add, asked before a ban/unban, never inside a transaction; a typed EnvironmentUserHostRefusal (409 owner/admin, 403 DEVELOPER_ORGANIZATION_MEMBER_LIMIT_REACHED) refuses the operation (ban/unban write nothing; a refused add is taken back out, per row on import); other host failures are fail-open and reported per row. Events carry actorCloudUserId from the administrator's linked objectstack-cloud account only. Managed 409 wording is provisional in one block of cloud-managed.ts. The PR owes a contract review at CONTRACT_REVIEW_TIER (narrowing) from the new review agent.",
"tests": "plugin-auth pending-sso-users.test.ts 35 tests and pending-sso-seams.test.ts, plus appended describes in implicit-account-linking.test.ts and password-reset-ends-sessions.test.ts; CONTROL legs for env_native and idp_provisioned rows and for the admin plugin mounted. 25 ablations, all red: A1-A16 (password arms, session refusals, ban writer, door refusals, marker on insert, one-read columns) and B1-B9 (host refusals on ban/unban, refusal status filter, refusal recognition, take-back on add, refused re-add, cloud id provider filter, cloud id on the ban event, take-back of grants and membership). plugin-auth full suite 270 files, 5169 passed, 10 skipped; platform-objects 122 files, 1958 passed; typecheck exit 0.",
"gates": "dispatch-gates --commands: 108 families, all run with </dev/null, exit codes recorded; --ran: 108 derived, 108 run, 0 NOT-MEASURED (derived zero). Gates reading test sources re-run after the dogfood-table change: all exit 0. pnpm lint exit 0. Record: out/33181-gates-ran-be43f4e1.list.",
"dogfood_battery": "ran (the title carries ! and Clause-② is narrowing): the full run failed only the two admin-route sweeps, naming the two new doors; both are now classified (gate first, the admin gets 409 off managed) and the two files re-run green, 15 passed; 461 other files passed.",
"mcp_calls": "reads only (issue_read, pull_request_read); 0 writes",
"api_writes": "2: relay pr_create (#33227, assignee os-tesla, read back 14614/14614 bytes identical) and this os-dev-report comment via post-stamped",
"open_questions": [
"The four managed 409 sentences are provisional until the maintainer's text is quoted on this card."
],
"follow_ups": [
"Seat to file out/33181-fu-seam.md: a pending-only remove door that cancels the invitation, and where the durable outbox with retry and per-row invitation status lives (comment 6870710213).",
"For #33186: no console entry for the two doors yet; the sys_user ban_user / unban_user actions keep requiresFeature: 'admin'."
],
"security_findings": "none new in this report",
"out_of_scope_findings": []
}
Release: session_01L9qibzuZJBQY4wUQFJbkfx · seat domain:server#7 signs off on the maintainer's word 「所有座位当前任务处理完,合并后就下班」 (2026-11-14T04:35Z, project chat) and 「各座位自己的契约复审也暂停,等新的 review agent 上线后复审」 (2026-11-14T04:37Z) · back to pm:queue for the next claimant · 2026-11-14T06:10Z
Resume-from: claude/project-thread-cl505i@be43f4e112bf6e279bc4c8ebb8ac25cdf938bf61
The managed-mode 409 sentences are provisional (one block in cloud-managed.ts) until the maintainer's exact text is quoted on this card. The rulings quoted in 6870710213 do not carry them.
The shape is the claim amendments 6869729952 and 6870557312, plus two items taken from the 6870710213 gap list: typed host refusals before ban and unban, and actorCloudUserId read from the linked cloud account.
Maintainer decision recorded · 2026-11-14T14:37Z: the maintainer chose 「用 dev 的文案」 on the seat's decision card, which asked whether to use the dev's wording for the managed-mode 409 sentences or wait for the original text. The sentences in cloud-managed.ts on PR #33227 ("Add them in Setup → Users instead; they sign in through that identity provider") are therefore final, not provisional. A later rewording is its own card.
Claim: resume after the 04:35Z sign-off, card thread · 2026-11-14T15:47Z · the seat is back on duty for review and landing only (「你现在可以自己契约复审了。」 2026-11-14T14:17Z; 「车道座位应该使用pm-dispatch 技能审核和落地pr」 2026-11-14T14:32Z); PR #33227
Session: session_01L9qibvhGW6DCBPjrcAPjvh
Account: os-tesla
Branch: claude/project-thread-cl505i
Worktree: objectstack-issue-33181
Domain: domain:server
Seat: domain:server#7
File surface: unchanged — claim 6869596244 with amendments 6869729952 and 6870557312. Stop on breach.
Container & model: L, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: high
Clause-②: yes (narrowing), as declared on PR #33227 and reviewed at CONTRACT_REVIEW_TIER (records 6879138774, 6879497274)
Metadata-protocol: none
Responsibility: managed environments' add-person and ban doors on Free / Team kernels (plugin-auth), objectstack | every managed-environment admin | 18.4.0 onward
Thread-read: 6879497274
Premise: re-measured by the card thread on 84a7069 (dogfood battery green on e1637d8)
Serial constraints cleared: #33177 merged before code; no other open PR of this seat changes these doors
Activity
objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: routed →
domain:server· p1 ·pm:queue· 2026-11-14T00:45Z⛔ Not a claim.
session_01Q4EjjPP1zuWBNq3nBXVei9). This is a child of objectstack-ai/cloud#4465, which records rulings 1–10: people are added in the environment, and credentials stay in the cloud.plugin-auth. The pending marker must be its own value, neverenv_native, so every password door refuses it.objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim: PM loop round 14, card thread · 2026-11-14T01:44Z · p1 on the maintainer's word 「都是p1,车道自己认领就可以」 (triage 6868743330)
Session:
session_01L9qibvhGW6DCBPjrcAPjvhAccount:
os-teslaBranch:
claude/project-thread-cl505iWorktree:
objectstack-issue-33181Domain:
domain:serverSeat:
domain:server#7File surface:
packages/plugins/plugin-auth/src/— a new pending-user door file, the password doors' refusal of the pending marker,implicit-account-linking.ts(the first-SSO bind),cloud-managed.ts(the managed-mode 409 wording), the plugin wiring and the host seam's type;packages/spec/src/only if the shape note names it and the seat accepts it; their tests; the auth docs page that lists these doors; one root changeset. Every file is named in a shape note before code. Stop on breach.Container & model:
L,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; PM default),effort: highClause-②: yes (widening) — a new door adds pending users; refusing the new pending marker at the password doors narrows nothing, since no row carries it on
main; any existing door that newly refuses something is declared as a narrowing arm in the shape noteMetadata-protocol: none — unless the marker lands in a spec enum, which the shape note states before code
Responsibility: managed environments have no working add-person door on Free / Team kernels (
plugin-auth: the better-auth admin plugin mounts only with SCIM, andadmin/import-usersanswers 501), objectstack | the cloud adds people only through its own console | every managed-environment admin who needs a person to exist before their first sign-in, and the seeds and approval flows that point at themThread-read: 6868743330
Premise: re-measure — the card's line references (
auth-manager-plugin-list.ts:211,auth-plugin.ts:4604,admin-user-endpoints.ts:1120-1136) and whetheradmin/ban-useranswers on a Free hosted kernel are measured atorigin/mainfirstSerial constraints cleared: NOT yet for code — security#2's PR #33177 (#32087 item 5) changes the same password doors; measurement and the shape note proceed now, code starts only after #33177 has merged, on top of it. The maintainer's rulings 1–10 on objectstack-ai/cloud#4465 are outside this session's reach and are being quoted onto this card; nothing is inferred from them meanwhile.
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim amendment to this seat's claim 6869596244 on #33181 · 2026-11-14T01:52Z: the seat accepts the shape note
out/33181-proposed-shape.md(measured atorigin/main8835532), with these choices.The file surface adds:
packages/platform-objects/src/identity/sys-user.object.ts: one new optionidp_pendingon the existingsourceselect, plus its description. The pending marker has no other home.translations/*.objects.generated.tsthatcheck-i18n-bundles.mjs --writeregenerates from it. They are regenerated, never hand-edited.plugin-auth, the files the note names:pending-sso-users.ts(new),auth-plugin.ts,admin-user-endpoints.ts,auth-manager-before-hook.ts,sso-only-local-password.ts,auth-manager-database-hooks.ts,auth-manager.ts,auth-manager-plugin-list.ts/auth-schema-config.ts,cloud-managed.ts,index.ts, and the header ofimplicit-account-linking.ts;content/docs/permissions/authentication.mdx.The seat's choices:
409.Metadata-protocol: none: a platform-object select option, not a spec enum.admin/ban-user/unban-userdoors on kernels without the admin plugin, rather than adding a second vocabulary. That carries a declared narrowing arm, so the PR declaresClause-②: yes (widening, narrowing)with the BREAKING banner, and the contract review runs atCONTRACT_REVIEW_TIER.main.The exact sentences and any point the maintainer's rulings on objectstack-ai/cloud#4465 fix are taken from those rulings once they are quoted on this card.
Code still starts only after PR #33177 has merged.
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Second claim amendment to this seat's claim 6869596244 on #33181 · 2026-11-14T02:54Z: the file surface adds, all in
packages/plugins/plugin-auth/src/unless named otherwise:pending-sso-marker.ts,environment-user-host.ts,user-session-admission.ts(split out so the plugin wiring has no import cycle);admin-ban-endpoints.tsanduser-ban-write.ts: the engine writer behindadmin/ban-user/unban-useron kernels without the admin plugin;set-initial-password.ts: an optionalbeforeWrite, so the pending check runs after the body read;service-account-identity.ts: the onesys_userread per session also carries the admission columns;auth-route-ledger.tsand its conformance list (the new routes);packages/platform-objects/src/identity/sys-user-identity-source-label.test.ts.auth-manager-plugin-list.tsandauth-schema-config.tsleave the surface; they are not touched.The pending row is written once, born pending, by the engine as the system (the service-account door's pattern), not through the vendor user factory. The exact wording of the managed-mode 409 sentences sits in one block in
cloud-managed.tsand is replaced by the maintainer's text from objectstack-ai/cloud#4465 once it is quoted on this card.objectstack-fleet commentedon Nov 14, 2026
repo:cloud#5 · hotlong · session_01Q4EjjPP1zuWBNq3nBXVei9
Ruling text relayed 2026-11-14T03:06Z, on the maintainer's request in seat session
session_01Q4EjjPP1zuWBNq3nBXVei9: 「server agent 项目读不到 cloud 仓库,请把原文贴到两张卡上」. This card is child 1a of objectstack-ai/cloud#4465 (private repo). Below is the verbatim text of that card's body as last edited at 2026-11-14T03:05Z: the rulings that bear on child 1a (1–5, 9, 10), the environment-side execution terms, the edge paths, and the open facts that name child 1a. Rulings 6 (console invite door), 7 (ADR note) and 8 (direct redirect, carried by #33183) do not bear on this card and are left out. The cloud code paths cited below are in the cloud repo and are given as references, not as files in this repo.Rulings (the maintainer, 2026-11-13), verbatim
Execution terms for the environment (children 1a / 2b), verbatim
Edge paths the children must cover, verbatim
Open facts naming child 1a, verbatim
Rulings recorded after the body (comment 6870693029 on cloud#4465)
For this card: D-3 means stored local password hashes on hosted are refused, not deleted, so every password door refuses rather than clears. D-2 means no one-time recovery link is built; ruling 10's emergency access is not extended here.
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibvhGW6DCBPjrcAPjvh
os-dev-report
{ "issue": 33181, "status": "done", "branch": "claude/project-thread-cl505i", "pr": "https://github.com/objectstack-ai/objectstack/pull/33227", "head": "be43f4e1", "session": "session_01L9qibvhGW6DCBPjrcAPjvh", "premise_still_valid": true, "summary": "Draft PR, one commit on origin/main 7257f57a. On a cloud-managed environment, POST /admin/add-sso-user and /admin/import-sso-users (platform-admin gated, no admin-plugin dependency, 409 RESOURCE_CONFLICT off managed) write a person born sys_user.source=idp_pending by one engine insert as the system, attributed to the administrator, with positions, permission sets (caller's context, one unit of work), membership and manager. Every password door (set-user-password, set-initial-password, reset-password, phone-number/reset-password) answers 409 for a pending row; session creation answers 403; the first platform-IdP sign-in binds (implicit-linking rule 2) and stampIdentitySource moves it to idp_provisioned. admin/ban-user and unban-user now work without the admin plugin (engine writer, session refusal with the vendor's 403 BANNED_USER). Host seam environmentUserHost: told after an add, asked before a ban/unban, never inside a transaction; a typed EnvironmentUserHostRefusal (409 owner/admin, 403 DEVELOPER_ORGANIZATION_MEMBER_LIMIT_REACHED) refuses the operation (ban/unban write nothing; a refused add is taken back out, per row on import); other host failures are fail-open and reported per row. Events carry actorCloudUserId from the administrator's linked objectstack-cloud account only. Managed 409 wording is provisional in one block of cloud-managed.ts. The PR owes a contract review at CONTRACT_REVIEW_TIER (narrowing) from the new review agent.", "tests": "plugin-auth pending-sso-users.test.ts 35 tests and pending-sso-seams.test.ts, plus appended describes in implicit-account-linking.test.ts and password-reset-ends-sessions.test.ts; CONTROL legs for env_native and idp_provisioned rows and for the admin plugin mounted. 25 ablations, all red: A1-A16 (password arms, session refusals, ban writer, door refusals, marker on insert, one-read columns) and B1-B9 (host refusals on ban/unban, refusal status filter, refusal recognition, take-back on add, refused re-add, cloud id provider filter, cloud id on the ban event, take-back of grants and membership). plugin-auth full suite 270 files, 5169 passed, 10 skipped; platform-objects 122 files, 1958 passed; typecheck exit 0.", "gates": "dispatch-gates --commands: 108 families, all run with </dev/null, exit codes recorded; --ran: 108 derived, 108 run, 0 NOT-MEASURED (derived zero). Gates reading test sources re-run after the dogfood-table change: all exit 0. pnpm lint exit 0. Record: out/33181-gates-ran-be43f4e1.list.", "dogfood_battery": "ran (the title carries ! and Clause-② is narrowing): the full run failed only the two admin-route sweeps, naming the two new doors; both are now classified (gate first, the admin gets 409 off managed) and the two files re-run green, 15 passed; 461 other files passed.", "mcp_calls": "reads only (issue_read, pull_request_read); 0 writes", "api_writes": "2: relay pr_create (#33227, assignee os-tesla, read back 14614/14614 bytes identical) and this os-dev-report comment via post-stamped", "open_questions": [ "The four managed 409 sentences are provisional until the maintainer's text is quoted on this card." ], "follow_ups": [ "Seat to file out/33181-fu-seam.md: a pending-only remove door that cancels the invitation, and where the durable outbox with retry and per-row invitation status lives (comment 6870710213).", "For #33186: no console entry for the two doors yet; the sys_user ban_user / unban_user actions keep requiresFeature: 'admin'." ], "security_findings": "none new in this report", "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Release: session_01L9qibzuZJBQY4wUQFJbkfx · seat domain:server#7 signs off on the maintainer's word 「所有座位当前任务处理完,合并后就下班」 (2026-11-14T04:35Z, project chat) and 「各座位自己的契约复审也暂停,等新的 review agent 上线后复审」 (2026-11-14T04:37Z) · back to pm:queue for the next claimant · 2026-11-14T06:10Z
Resume-from: claude/project-thread-cl505i@be43f4e112bf6e279bc4c8ebb8ac25cdf938bf61
CONTRACT_REVIEW_TIER(Clause-②: yes (narrowing): ban and unban answer on kernels without the admin plugin) from the new review agent, then ACCEPT and land.cloud-managed.ts) until the maintainer's exact text is quoted on this card. The rulings quoted in 6870710213 do not carry them.actorCloudUserIdread from the linked cloud account.ban_user/unban_userdroppingrequiresFeature: 'admin', as the PR body notes.objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Maintainer decision recorded · 2026-11-14T14:37Z: the maintainer chose 「用 dev 的文案」 on the seat's decision card, which asked whether to use the dev's wording for the managed-mode 409 sentences or wait for the original text. The sentences in
cloud-managed.tson PR #33227 ("Add them in Setup → Users instead; they sign in through that identity provider") are therefore final, not provisional. A later rewording is its own card.objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim: resume after the 04:35Z sign-off, card thread · 2026-11-14T15:47Z · the seat is back on duty for review and landing only (「你现在可以自己契约复审了。」 2026-11-14T14:17Z; 「车道座位应该使用pm-dispatch 技能审核和落地pr」 2026-11-14T14:32Z); PR #33227
Session:
session_01L9qibvhGW6DCBPjrcAPjvhAccount:
os-teslaBranch:
claude/project-thread-cl505iWorktree:
objectstack-issue-33181Domain:
domain:serverSeat:
domain:server#7File surface: unchanged — claim 6869596244 with amendments 6869729952 and 6870557312. Stop on breach.
Container & model:
L,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; PM default),effort: highClause-②: yes (narrowing), as declared on PR #33227 and reviewed at
CONTRACT_REVIEW_TIER(records 6879138774, 6879497274)Metadata-protocol: none
Responsibility: managed environments' add-person and ban doors on Free / Team kernels (
plugin-auth), objectstack | every managed-environment admin | 18.4.0 onwardThread-read: 6879497274
Premise: re-measured by the card thread on 84a7069 (dogfood battery green on e1637d8)
Serial constraints cleared: #33177 merged before code; no other open PR of this seat changes these doors
objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: H14 ·
+pm:blocking· 2026-11-14T17:50Z⛔ Not a claim; claim and state unchanged.
Open cards name this one in
Blocked-by:: #33186, #33187 (and #33228 waits on it). A blocker in flight carriespm:blocking.