Skip to content

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

Closed

Description

@objectstack-fleet

repo:cloud#3 · hotlong · session_01Q4EjjRhUZjdy8VXs6Kkur2

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).

维护者速读

IdP 把用户推进某个 SCIM 组以后,平台会建组、加成员,但不会因此给这个用户任何角色或权限集。企业版要求「IdP 里的组决定平台里的权限」,现在做不到。需要平台支持把 SCIM 组映射到角色或权限集。

Measured (cloud pin 2ffdb649 on the serve; objectstack 6ddf827236 read)

  • SCIM POST /api/v1/auth/scim/v2/Groups with the user as a member → 201. The user's sys_user_permission_set rows and sys_member.role are unchanged (cloud#3672 parks this as it.skip).
  • packages/plugins/plugin-auth/src/auth-manager-plugin-list.ts:798 calls scim({ connections, authentication, identity }) with no projection, so @better-auth/scim's group membership touches nothing in the platform's grant model.
  • last-admin-guard.ts names a SCIM group-mapping change as a write shape it guards, which describes a mapping that does not exist.

Expected

  • A declared mapping from a SCIM group (by displayName or externalId, per connection or per organization; the lane decides) to an organization role and/or permission sets. Membership add and remove apply and revoke the grant.
  • Grants go through the existing assignment doors (assignable-set boundary, last-admin guard), not around them. A mapping that would drop the last admin is refused as the guard refuses other shapes.
  • Each grant change writes the audit row the assignment door already writes, attributed to the SCIM connection.

Acceptance

  • Tests: push a mapped group with a member → the set is granted; remove the member → revoked; an unmapped group grants nothing; a mapping that would remove the last admin → refused as a SCIM 403.

Suggested-grade: p1 · Enterprise priority (maintainer).

Dedupe (2026-11-06): SCIM group role mapping → 21 hits (#27314 open is the bridges epic, a different surface; the rest closed); scim projection → 47 hits, top 4 closed and unrelated. None covers this gap.

Activity

  1. added
    bugSomething isn't working
    priority:p1High: required for production / M2
    pm:queueReady for the PM dispatch loop
    repo:cloudCard routed whole to the cloud PM: needs cloud code, a producer or a fact (cloud owns it to closure)
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 6, 2026
  2. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p1 kept · domain:server · 2026-11-06T14:31Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Claim: PM loop round 1 · 2026-11-06T14:48Z
    Session: session_016WV4czvZykUqhYxYXSSDt4
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: the card thread's designated claude/project-thread-* branch, re-posted in a whole claim once the thread reports it
    Worktree: objectstack-issue-30959
    Domain: domain:server
    Seat: domain:server#4
    File surface: the SCIM wiring and a group projection in packages/plugins/plugin-auth/src/** (auth-manager-plugin-list.ts, scim-connection-service.ts, a new projection module, last-admin-guard.ts only where it names the SCIM mapping shape); the existing role and permission-set assignment doors it calls (read, or a caller face exposed with no new judgment); their tests and dogfood; content/docs/** sentences on SCIM provisioning; one root .changeset/ file. ⛔ packages/spec/**: if the mapping needs a published key, schema or settings key, the dev stops after measuring and the seat takes the design choice to the maintainer and files the domain:spec sub-card. ⛔ ui/**, skills/** (stop on breach; explain in the report)
    Container & model: L, mode:thread, model: default, effort: xhigh (p1)
    Clause-②: yes (widening) (provisional: a SCIM group push starts granting roles and permission sets; the dev measures and reports the arm)
    Metadata-protocol: none (provisional; added only through the spec sub-card)
    Responsibility: n/a — capability gap with a named consumer (objectstack-ai/cloud#3667), not a regression
    Thread-read: 6687271791
    Premise: card body (Enterprise priority, 「cloud 多了几个企业版的任务,优先处理」) and triage 6687271791 (p1 kept).

    • A declared mapping from a SCIM group (by displayName or externalId) to an organization role and/or permission sets. Adding a member grants, removing one revokes, and an unmapped group grants nothing.
    • Every grant goes through the existing assignment doors (assignable-set boundary, last-admin guard) and writes their audit row, attributed to the SCIM connection. A mapping change that would drop the last admin is refused as a SCIM 403.
    • Whether the mapping is a spec key or a settings row is measured first and decided before any build.
      Serial constraints cleared: no open PR touches packages/plugins/plugin-auth (searched at claim); the dev re-reads open PRs on it at branch start

    Contract review owed (a widening of a security boundary: a new grant path) before the queue.

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 6, 2026
  5. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Claim: PM loop round 1 (whole claim re-posted with the branch) · 2026-11-06T14:52Z
    Session: session_016WV4czvZykUqhYxYXSSDt4
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-qta161
    Dev session: session_016WV4cwCnS3MmnAfNkXm8MS (card thread)
    Worktree: objectstack-issue-30959
    Domain: domain:server
    Seat: domain:server#4
    File surface: the SCIM wiring and a group projection in packages/plugins/plugin-auth/src/** (auth-manager-plugin-list.ts, scim-connection-service.ts, a new projection module, last-admin-guard.ts only where it names the SCIM mapping shape); the existing role and permission-set assignment doors it calls (read, or a caller face exposed with no new judgment); their tests and dogfood; content/docs/** sentences on SCIM provisioning; one root .changeset/ file. ⛔ packages/spec/**: if the mapping needs a published key, schema or settings key, the dev stops after measuring and the seat takes the design choice to the maintainer and files the domain:spec sub-card. ⛔ ui/**, skills/** (stop on breach; explain in the report)
    Container & model: L, mode:thread, model: default, effort: xhigh (p1)
    Clause-②: yes (widening) (provisional: a SCIM group push starts granting roles and permission sets; the dev measures and reports the arm)
    Metadata-protocol: none (provisional; added only through the spec sub-card)
    Responsibility: n/a — capability gap with a named consumer (objectstack-ai/cloud#3667), not a regression
    Thread-read: 6687271791
    Premise: card body (Enterprise priority, 「cloud 多了几个企业版的任务,优先处理」) and triage 6687271791 (p1 kept).

    • A declared mapping from a SCIM group (by displayName or externalId) to an organization role and/or permission sets. Adding a member grants, removing one revokes, and an unmapped group grants nothing.
    • Every grant goes through the existing assignment doors (assignable-set boundary, last-admin guard) and writes their audit row, attributed to the SCIM connection. A mapping change that would drop the last admin is refused as a SCIM 403.
    • Whether the mapping is a spec key or a settings row is measured first and decided before any build.
      Serial constraints cleared: no open PR touches packages/plugins/plugin-auth (searched at claim); the dev re-reads open PRs on it at branch start

    Contract review owed (a widening of a security boundary: a new grant path) before the queue.

  6. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 6, 2026
  7. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Parked · 2026-11-06T15:06Z · section 1 measured (/mnt/project-files/server-lane-seat4/30959/section1-measurements.md). The build is serial behind two sibling cards that edit the same files (scim-connection-service.ts, auth-manager-plugin-list.ts). This card rides #30960's SCIM write attribution (svc:scim:<connection>) instead of building its own. The storage of the mapping, and whether an IdP group may confer admin standing, are with the maintainer on a decision card. ADR-0134 D4 ("no group→role mapping in V1") needs an amendment, so the PR will be Tier H. The claim (6687734014) and the card thread stand.

    Blocked-by: #30960
    Blocked-by: #30958

  8. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4czvZykUqhYxYXSSDt4

    Release: claim 6687734014 · 2026-11-06T16:25Z · server seat 4 is signing off on the maintainer's word, and this card has not started building. It stays pm:blocked (Blocked-by: #30960, Blocked-by: #30958). The assignee is removed, so the next seat claims it fresh.

    Handoff for that seat:

    • Section 1 is measured: /mnt/project-files/server-lane-seat4/30959/section1-measurements.md (project files; the summary is in the parked note above).
    • Settled by the seat: match a group by externalId, then displayName. Ride 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's SCIM write attribution (svc:scim:<connection>); don't build a second one.
    • Still open, for the maintainer: where the mapping lives (recommended: a per-connection platform-object row, sets only) and whether an IdP group may confer admin standing (recommended: no in V1). The seat's decision card on this was withdrawn at sign-off, so the next seat re-asks.
    • Owed: an ADR-0134 D4 amendment ("no group→role mapping in V1"), a fable-tier surface, so the PR is Tier H. One platform-object-names constant in spec needs the spec lane's nod.
  9. 22 remaining items

  10. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5mEnsnzoPLq43wQyYy
    os-dev-report
    {
    "issue": 30959,
    "status": "done",
    "branch": "claude/project-thread-dv4dek",
    "pr": "#31443",
    "head": "776f80e0db449e847b087b85bb9da8ea338170a0",
    "session": "session_01FEkQ5mEnsnzoPLq43wQyYy",
    "premise_still_valid": true,
    "summary": "A SCIM group push now grants the ordinary permission set a sys_idp_group_mapping row names, in the organization that owns the connection, written through the ObjectQL engine inside the SCIM transaction as svc:scim:CONNECTION_ID; removing the member revokes it, and reconcile removes only grants carrying its own reason marker. Mappings are written only by POST /api/v1/auth/admin/scim/set-group-mapping and /delete-group-mapping behind the mint-credential platform-admin gate. The save refuses every set outside the organization boundary (400 VALIDATION_FAILED, permissionSet, rule_violation) using plugin-security's own organizationBoundaryFailure, lifted verbatim to a module function and served as an optional security-service member; no package dependency, no copy of the list, fail closed (503) without it. last-admin-guard texts no longer name a SCIM group mapping.",
    "security_member": "ISecurityService.organizationBoundaryFailure?(setName: string) resolving to string or null (packages/spec/src/contracts/security-service.ts, OPTIONAL, JSDoc says feature-detect and fail closed); DECLARED_MEMBERS row 'optional'. The only implementer that serves it is plugin-security's Object.assign extension; every other ISecurityService implementer is untouched and still type-checks (tsc --noEmit exit 0 for spec, plugin-security, plugin-auth, platform-objects; the 128-gate round includes check:type-check-coverage and check:init-service-contract, both exit 0). Seat-approved via claim amendments 6718415748 and 6718429681.",
    "tests": "src/scim-group-projection.test.ts 8/8 (rows 1-5, CONTROL unmapped, CONTROL hand-made admin_full_access + same-set grant, save/delete reprojects). Refusal rows assert status 400 + code VALIDATION_FAILED + fields [permissionSet, rule_violation] + no row stored. Ablations via scripts/ablation-replace.mjs, each blob restored == HEAD: A boundary refusal disabled -> rows 3,4 red; B reason-marker check deleted -> hand-made CONTROL red; C group match removed from roles.map -> unmapped CONTROL red; D projection wiring renamed -> rows 1,2 + reproject red; E writer without SCIM context -> rows 1,2 red (actor assertions). Row 5 is a regression pin, not ablated. Suites: plugin-auth 241 files / 4256 passed / 10 skipped; plugin-security exit 0; platform-objects 120 files / 1751 after the bundle-ownership row (was the one red); dogfood admin-platform-admin-standing + admin-route-nonadmin-refusal + admin-identity-audit-trail 3 files / 19 passed.",
    "gates": "dispatch-gates --commands on final head 776f80e derived 128 families; all 128 run, every exit 0 (captured before any pipe, per-command logs); --ran: 128 run, 0 NOT-MEASURED, 0 UNRUN. First round (98 families on an earlier head) found check-tenant-audit-census (untyped receivers + count drift), check:auth-mount-ledger (loop-spelled mounts), check:platform-object-tenancy-census (new object), all fixed; plugin-teardown-shape --self-test and dual-build-cjs-loads exit 3 there were prerequisites (pinned commit fetched, full build run) and both exit 0 in the final round. Also check:i18n-coverage exit 0, eslint --no-inline-config over plugin-auth/plugin-security/platform-objects/spec/dogfood exit 0, tsc --noEmit exit 0 for the four packages. CI check-runs: not yet read (PR just opened).",
    "line_budget": "39 files, +1650 -107 (1757). Generated: 13 translation bundle files +342 (en regenerated; six locales hand-translated, copy-hashes dropped by re-extract) and 3 census artefacts +61 -49 (tenant-audit page, its counts file, tenancy census JSON; ~20 of the page lines are hand-corrected prose figures the checker holds to the census) = 452. Authored: 23 files, +1247 -58 = 1305. Seat ruled authored lines count; under the ~1500 budget, one build PR.",
    "files_changed": {
    "authored": [
    ".changeset/30959-scim-group-permission-set-mapping.md",
    "packages/platform-objects/scripts/i18n-extract.config.ts",
    "packages/platform-objects/src/apps/translations/bundle-ownership.test.ts",
    "packages/platform-objects/src/identity/index.ts",
    "packages/platform-objects/src/identity/sys-idp-group-mapping.object.ts",
    "packages/plugins/plugin-auth/src/auth-manager-plugin-list.ts",
    "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/idp-group-mapping-admin.ts",
    "packages/plugins/plugin-auth/src/last-admin-guard.test.ts",
    "packages/plugins/plugin-auth/src/last-admin-guard.ts",
    "packages/plugins/plugin-auth/src/manifest.ts",
    "packages/plugins/plugin-auth/src/scim-group-projection.test.ts",
    "packages/plugins/plugin-auth/src/scim-group-projection.ts",
    "packages/plugins/plugin-security/src/delegated-admin-gate.ts",
    "packages/plugins/plugin-security/src/registered-security-service-members.pin.test.ts",
    "packages/plugins/plugin-security/src/security-plugin-security-service.ts",
    "packages/qa/dogfood/test/admin-platform-admin-standing.dogfood.test.ts",
    "packages/qa/dogfood/test/admin-route-nonadmin-refusal.dogfood.test.ts",
    "packages/spec/src/contracts/security-service.ts",
    "packages/spec/src/system/constants/platform-object-names.ts"
    ],
    "generated_review_may_skip": [
    "packages/platform-objects/src/apps/translations/{ar,en,es-ES,fr,ja-JP,zh-CN,zh-Hant}.objects.generated.ts",
    "packages/platform-objects/src/apps/translations/{ar,es-ES,fr,ja-JP,zh-CN,zh-Hant}.source-hashes.generated.ts",
    "content/docs/permissions/tenant-audit-census.mdx (generated tables + hand-corrected prose figures)",
    "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
    "scripts/platform-object-tenancy-census.json"
    ]
    },
    "deviations": [
    "packages/spec: besides the one PLATFORM_OBJECTS_BY_PACKAGE row, one optional ISecurityService member (seat option A, claim amendment 6718429681). No other spec edit.",
    "plugin-security: organizationBoundaryFailure lifted verbatim to a module-level function, private method now a one-line delegate, served on the security service; not exported from index.ts (claim amendment 6718415748).",
    "Beyond the acceptance rows: save/delete re-run the vendor's reconcileSCIMProjection for the connection's provisioning domains (current members updated at once), and roles.exists re-judges the boundary at grant time (warns once, grants nothing).",
    "Census artefacts regenerated and the tenant-audit page's prose figures updated (gates required it); outside the order's file list but no behaviour change.",
    "No Console UI for mappings (size budget); the doors are the only writer."
    ],
    "readings": [
    "Group matching is per row: a row names exactly one of group_external_id / group_display_name; externalId when the row has one, else exact displayName.",
    "source_kind is a closed select with the single value 'scim'; #30967 adds its SSO value.",
    "A desired set already held (any reason) is not inserted again; two provisioning domains projecting the same (set, org) share one row whose marker names the first writer.",
    "Metadata-protocol: none — no metadata type, authorable key or publish door changes; the new surface is a platform object and two admin REST doors (Clause-②: yes (widening))."
    ],
    "adr_draft": "Drafted: /mnt/project-files/server-lane-seat6/30959/adr-draft.md (ADR-0149 proposed number; mechanism, sys_idp_group_mapping storage, admin boundary, @better-auth/scim 1.7.12, ADR-0134 D4 pointer line). Goes up as the second PR from this branch after #31443 merges, Refs #30959; the build PR body names it as the follow-up.",
    "serial": "#30967 (claude/project-thread-xykd7v): whichever lands second merges origin/main once (no rebase) and re-runs plugin-auth + platform-objects suites.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm; the three edited/related dogfood files ran: 3/3 files, 19/19 tests.",
    "mcp_calls": "3 — mcp__github__issue_read x3 (card read). No MCP write.",
    "api_writes": "4 — git push x2 (WIP 2e9c46f, final 776f80e); relay pr_create x1 (repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, run 42462055458, read-back 9597/9597 bytes identical, assignees none, no labels); this report comment x1 via post-stamped.mjs.",
    "open_questions": [],
    "security_findings": "withheld",
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  11. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ

    落地 · 2026-11-08T17:13Z

    reading value
    PR #31443 MERGED 2026-11-08T17:13Z, merge commit ed4b8322 (ACCEPT 6724178557; contract review PASS 6719306407, 6722234751, 6723129278 and 6723714687 at CONTRACT_REVIEW_TIER)
    #30959 stays open: the PR says Refs #30959; the ADR PR closes it

    Landed: the build half of the ruling recorded at 6718345088.

    • Groups that an IdP pushes over SCIM can grant one ordinary permission set to their members, through a sys_idp_group_mapping row that a platform admin saves. Removing a member from the group revokes the grant.
    • A mapping can never grant an admin set. The check runs through plugin-security's optional organizationBoundaryFailure, and the save is refused when that member is absent.
    • Translations in all nine locales, the ADR-0131 D10 inventory row, and patch changesets for plugin-auth, plugin-security, platform-objects, spec and cli (Clause-②: yes (widening)).
  12. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ

    Release: claim 6718392258 · 2026-11-08T17:14Z · server seat 6 is going off duty on the maintainer's word 「server 车道当前任务处理完,合并久就下班」 (2026-11-08T15:48Z). The build PR #31443 landed (record above), and the card's second PR was not started, so the card goes back to pm:queue with no assignee.
    Produce: #31443 (merged). Nothing unmerged to resume; the ADR PR starts fresh from main.
    Next: the ADR PR that the claim scopes.

    • It adds one new ADR under docs/adr/ recording the decision: mechanism, storage, admin boundary, vendor @better-auth/scim 1.7.12. It also adds one pointer line in ADR-0134 D4.
    • A draft is at /mnt/project-files/server-lane-seat6/30959/adr-draft.md (project files). It proposes ADR-0149; re-check the next free number on main.
    • Tier H: the maintainer merges it. It says Fixes #30959. Its symbol anchors now resolve against landed code.
  13. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 8, 2026
  14. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 8, 2026
  15. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    Claim: PM loop round 3 · 2026-11-08T18:01Z
    Session: session_01ADHkmSoGBrHrzTArx233j6 (card thread, dev) · seat session_01ADHkmQKZzp4DLtqiCkZZRM
    Account: os-steve
    Branch: claude/project-thread-1at98g
    Worktree: objectstack-issue-30959
    Domain: domain:server
    Seat: domain:server#2
    File surface: one new docs/adr/0NNN-*.md, one pointer line in docs/adr/0134-*.md (D4), docs/adr/README.md index row. ⛔ Nothing else
    Container & model: S (docs-only, governed), mode:thread, model: default tier to draft; the seat's contract review runs at CONTRACT_REVIEW_TIER by a reviewer other than the drafter, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — the card's second PR, recording decisions already ruled
    Thread-read: 6724537840
    Premise: holds — read at claim on origin/main 69244406: the build landed (PR #31443, record 6724527199); the ADR's symbol anchors resolve against landed code. Seat 6's draft path /mnt/project-files/server-lane-seat6/30959/ is absent; the ADR is written from the rulings on this card and the merged code
    Serial constraints cleared: ADR numbers on origin/main end at 0149; open PRs hold 0150 (#31586) and 0151 (#31615), so this ADR takes the next number free across main AND open PRs (0152 at claim) and re-checks after merging main. #31586 and #31615 also edit docs/adr/README.md: an index-row conflict only, resolved by merging main. No open PR touches ADR-0134.

    Scope: the card's last PR; it says Fixes #30959. The ADR records mechanism, storage, admin boundary and the vendored @better-auth/scim version as ruled (fork 1 (a), fork 2 no) and quotes each ruling by comment id; it decides nothing new, and anything that would be a new decision goes to open_questions. Tier H: the PR stays draft, skip-changeset through pr_create; the seat hands it to an approver after its contract review. Order: /mnt/project-files/server-seat2/standard-order.md + /mnt/project-files/server-seat2/30959-delta.md. Summons: the maintainer's 「并发都是5」 (project chat, 2026-11-08T16:13Z).

  16. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmSoGBrHrzTArx233j6
    os-dev-report

    {
      "issue": 30959,
      "status": "done",
      "branch": "claude/project-thread-1at98g",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/31636",
      "head": "fcd6553c1463678dd4d1e94858d14f0d09bdd2b4",
      "session": "session_01ADHkmSoGBrHrzTArx233j6",
      "premise_still_valid": true,
      "summary": "Draft PR #31636 (Fixes #30959, Tier H, skip-changeset) adds ADR-0152, recording the three forks ruled in 6718345088 (verbatim 「以上都同意」 on analysis 6710730984): D1 fork 1 (a) per-connection sys_idp_group_mapping row written behind the mint-credential platform-admin gate, with the ruling's SSO build note carried and the SSO half left to #30967; D2 fork 2 no, an IdP group never confers administrator standing, refused at save by plugin-security organizationBoundaryFailure, the card's last-admin 403 line replaced; D3 fork 3 (i), new ADR plus one pointer line under ADR-0134 D4 (D4 text and status line unchanged). A separate section records the mechanism #31443 landed (ed4b8322) as anchored facts, not decisions, and the vendor fact measured on the installed package: @better-auth/scim 1.7.12 and runSCIMApplicationCallback passing only APIError through. Number 0152 because main ends at 0149 and open PRs #31586/#31615 hold 0150/0151; the ADR README index is regenerated.",
      "tests": "No tests: docs-only diff (docs/adr/** only); nothing ablated. Anchor proof: pnpm check:adr-symbol-anchors on head fcd6553c exit 0, '3297 anchors across 152 records resolve — 873 symbol (846 declaration, 27 literal), 2373 file-level'; on origin/main 69244406 '3273 anchors across 151 records', 856 symbol, 2366 file-level; delta +17 symbol / +7 file-level = this record's anchors, all resolved.",
      "gates": "On head fcd6553c (git rev-parse --short HEAD after the last commit): dispatch-gates --commands --repo objectstack-ai/objectstack derived 21 commands for 3 paths; all 21 exit 0, exit captured before any pipe, each stdin /dev/null. check:doc-formula-expressions after turbo build of @objectstack/formula + @objectstack/lint under os-verify-lock (VERDICT command-exit 0, 99 s). --ran reconciliation: '21 derived famil(ies) accounted for — 21 run, 0 NOT-MEASURED (a DERIVED zero)'. Named: check:adr-symbol-anchors 0, check:adr-index 0 ('README.md is current'), check:adr-anchors 0, check:adr-links 0, check:nul-bytes 0, check:pm-governed-merges 0. pnpm lint: n/a, no package touched. CI check-runs: not read (PR just opened); in_progress.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "3 files, +204 -3: new ADR +198, ADR-0134 +2 (one blockquote line + blank), README index +4 -3 (generated by pnpm adr:index)",
      "files_changed": {
        "authored": [
          "docs/adr/0152-scim-group-grants-only-an-ordinary-permission-set-through-a-per-connection-mapping.md",
          "docs/adr/0134-env-side-scim-provisioning.md"
        ],
        "generated_review_may_skip": ["docs/adr/README.md"]
      },
      "deviations": [
        "Wrote and committed the ADR locally before the Claim named the branch; the first push waited until Claim 6725064238 named claude/project-thread-1at98g.",
        "The harness asks for an MCP assignee/reviewer write after a PR opens; skipped per the standard order (no MCP writes). pr_create carried assignees os-steve; the relay requests the governed approvers on a Tier H diff."
      ],
      "mcp_calls": "6 — all reads: mcp__github__issue_read x5 (30959 get, 30959 get_comments x4), mcp__github__pull_request_read x1 (31636 get). No MCP write.",
      "api_writes": "3 — git push x1 (fcd6553c); relay pr_create x1 (repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, run 42508423429, read-back 6029/6029 bytes identical, assignees os-steve, label skip-changeset confirmed by pull_request_read); this os-dev-report comment x1 via post-stamped.mjs. Reads outside MCP: 6 gh api GET search/issues (ADR number checks).",
      "open_questions": [
        {
          "question": "Status line wording: 'Accepted — implemented, 2026-11-08' (README status-hygiene convention, implementation already landed in #31443) or 'Proposed' until the maintainer's hand-merge?",
          "options": ["A keep Accepted — implemented (ADR-0148/0149 precedent: Accepted from the ruling, the merge is the acceptance act)", "B Proposed until merge, flipped by a later PR"],
          "recommendation": "A, because the ruling is recorded (6718345088) and the implementation is on main; B costs a second governed PR for one word."
        },
        {
          "question": "Keep the section 'The mechanism as landed' (anchored facts about #31443's build choices: per-row group matching, grant-time boundary re-judge, reason marker, re-projection on save) in the ADR?",
          "options": ["A keep, labelled as facts not decisions (ADR-0134 vendor-version-fact precedent; anchors make drift loud)", "B trim to the three ruled forks only"],
          "recommendation": "A, because the card's fork 3 ruling names 'mechanism' as part of what the ADR records, and the section says it decides nothing."
        }
      ],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "class: none (doc drift, not filed) · reach: n/a · ADR-0134's vendor-version table still names 1.7.2 as the pin; main pins 1.7.12. ADR-0152 restates the fact; ADR-0134's dated table left as written (append-only, outside the file surface) · carrier: none"
      ]
    }

    Stamped 2026-11-08T18:09Z.


    Generated by Claude Code

  17. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    ACCEPT → PR #31636 comment 6725310167 · head fcd6553c · 2026-11-08T18:24Z · landing: Tier H, draft, handed to GOVERNED_APPROVERS (os-zhuang, hotlong); contract review 6725302158 PASS

  18. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    落地 · 2026-11-08T22:38Z

    reading value
    PR #31636 MERGED 2026-11-08T22:37Z, merge commit 13f9e8e7 (ACCEPT 6725310167 at fcd6553c; contract review PASS 6725302158 at CONTRACT_REVIEW_TIER; Tier H, enqueued by GOVERNED_APPROVERS os-zhuang; README-index conflict after ADR-0150 fixed at 47eb2197 by pnpm adr:index only, request 6727584331)
    #30959 closed (behaviour landed in #30967 item 3 / PR #31657 and #31448; this PR records the decision)

    Landed:

    • ADR-0152 (Accepted): a SCIM group grants only an ordinary permission set, through a per-connection mapping row that a platform administrator writes; the same model serves SSO groups by providerId.
    • ADR-0134 gains its back-pointer; the ADR index lists ADR-0152 beside ADR-0150.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions