Skip to content

docs(capabilities): capabilities/approvals.mdx says no Console field or auth admin endpoint sets sys_user.manager_id; POST /api/v1/auth/admin/set-user-manager and the Set Manager row action do #22662

Description

@objectstack-fleet

Filing gate ①, class (a): a published docs page states a product fact that is false. reach: the docs site page content/docs/capabilities/approvals.mdx. Filed by the domain:devx seat 1 (seat post #6023) · marchtian · session_01Q7Fy4uVkvBWgj9CLihdATJ, from the dev's out-of-scope finding on #22584 (report 6096192020, PR #22657). That PR's file surface is automation/approvals.mdx only, and this is a different defect class, so it was not edited there. Reader: triage, then the lane that owns content/docs/**. ⛔ Not a claim.

The sentence

content/docs/capabilities/approvals.mdx, the warn callout (about :15–:20 on origin/main):

it resolves sys_user.manager_id, and no Console field, data-API write or auth admin endpoint sets that column. Your own provisioning fills it — a seed or other system-context write, or a SCIM / directory-sync path your deployment supplies.

What the product has (read on origin/main)

  • packages/platform-objects/src/identity/sys-user.object.ts declares the row action set_user_manager (about :372), whose target is /api/v1/auth/admin/set-user-manager (about :378). The implementation is plugin-auth/src/admin-set-user-manager.ts, which the same file names.
  • content/docs/automation/approvals.mdx documents POST /api/v1/auth/admin/set-user-manager (about :82) and the Setup → Users → … → Set Manager path.

So the capabilities page tells an admin that the product cannot set a manager, while the automation page tells them how to. This is the same family as the manager_id "no product surface writes it" sentences that PR #22625 fixed on automation/approvals.mdx, left over on a second page.

Done when

  • The callout names the Set Manager action and the admin endpoint as the in-product way to fill manager_id, keeping provisioning (seed, SCIM or directory sync) as the bulk path.
  • It points to automation/approvals.mdx for the details, as it does now.
  • If the "until it is filled … the request waits" clause is kept, it matches the runtime on main: a manager entry that resolves to nobody adds no slot, and the node's onEmptyApprovers policy decides an empty slate (default admin_rescue). automation/approvals.mdx states this once PR docs(approvals): an entry that resolves to nobody leaves a slot per its kind, and an empty or literal-only slate goes to onEmptyApprovers #22657 lands.
  • A grep for the old phrase ("no Console field, data-API write or auth admin endpoint") over content/docs and skills/ is in the PR body.

Dedupe: MCP search_issues repo:objectstack-ai/objectstack manager_id set-user-manager → 1 hit, #10153 (closed, the manager approver's organization screen), which is not this sentence. Dedupe words: capabilities approvals manager_id set-user-manager · no Console field writes manager_id docs.

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, documentation · priority:p3 · domain:devx · area:workflow · pm:queue. Accepted as the close-out of the "nothing writes manager_id" family

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T09:54Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01Q7Fy4uVkvBWgj9CLihdATJ
    Account: marchtian (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-22662-capabilities-set-manager
    Worktree: objectstack-issue-22662
    Domain: domain:devx
    Seat: domain:devx#1
    File surface: content/docs/capabilities/approvals.mdx (the warn callout, about :15–:20 on origin/main), plus any other hand-written content/docs/** page that the family grep triage 6096320437 asks for finds stating that nothing in the product sets manager_id. Each such page is named in the PR body. A hit in packages/spec/src/** or skills/** is ⛔ not edited. It is named in the PR body and the report, because the first is the spec lane's contract text and the second is Tier H. ⛔ No content/docs/references/**, ⛔ no content/docs/releases/**, ⛔ no runtime change. (Stop on breach; explain in the report.)
    Container & model: S, judged as M (the replacement must match the product: the Set Manager action, the admin endpoint and onEmptyApprovers on main), mode:subagent, model: opus — the default tier; dispatch-gates --tier: "no path-derived mandate"
    Clause-②: no
    Responsibility: n/a — not a defect card (a docs correction; no runtime change)
    Thread-read: 6096320437
    Serial constraints cleared: no open PR touches content/docs/capabilities/approvals.mdx (12 open PRs' file lists read). The family's other page, content/docs/automation/approvals.mdx, landed today in PR #22657 (ee3ae0360d) and is not in this surface. — read at 2026-10-10T10:06Z

    Labels in this act: pm:queue → pm:dispatched; assignee marchtian.

  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 22662,
    "status": "done",
    "branch": "claude/issue-22662-capabilities-set-manager",
    "pr": "#22681",
    "session": "session_01Q7Fy4uVkvBWgj9CLihdATJ",
    "premise_still_valid": true,
    "summary": "Premise confirmed on origin/main ee3ae03: content/docs/capabilities/approvals.mdx:17 said no Console field, data-API write or auth admin endpoint sets sys_user.manager_id, but sys-user.object.ts:372 declares the set_user_manager row action (target :378), and POST /api/v1/auth/admin/set-user-manager is mounted in plugin-auth auth-plugin.ts:2630 behind gateAdmin (the ADR-0068 platform-admin gate; the action is visible only when current_user.isPlatformAdmin == true and the user is not idp_provisioned). The capabilities callout now names Setup -> Users -> Set Manager and the endpoint as the in-product way to set it. Provisioning stays the bulk path (the admin bulk-import endpoint's manager_id column, plus seed, SCIM or directory sync). The 'request waits' clause was kept and reworded to match main: a manager-only step resolves to nobody and onEmptyApprovers decides; the default, admin_rescue, opens the request and leaves it waiting for an administrator. The widened family grep found one more false sentence of the same kind: content/docs/automation/approvals.mdx:96 said the admin bulk import does not write the column, but admin-import-users.ts has admitted manager_id since d438b3a (PR #18046). That clause was replaced on the same PR, which adds a surface the PR body names. There were no hits in packages/spec/src or skills/. One runtime string carries the same false clause (the os lint remedy); it is reported below and not edited.",
    "tests": "Head 9923026 (worktree clean, equal to the remote head). Build: os-verify-lock.sh -c "pnpm exec turbo run build --filter='@objectstack/lint...' --filter='@objectstack/client-react...' --concurrency=2" gave 35/35 tasks and 'VERDICT command-exit 0'. Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths, gave 40 commands; all 40 ran with $? captured before any pipe, and all 40 exited 0 (map in gates). Reconciliation with --ran and 'COMMAND :: exit CODE' records: '40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3)'. Verdict lines: check:doc-anchors '480 internal #fragment link(s) across 417 source file(s) all resolve'; spec check:docs '225 generated files in sync'; spec check:skill-examples '262 prose examples type-check'; lint check:doc-security-posture '28 ObjectSchema.create example(s) ... os validate-clean'; check:nul-bytes 'OK (scanned 10660 text file(s)'. Family grep on base ee3ae03 and head: instrument 1 (column and chain words) gave 61 lines in 27 files on the base and 65 in 27 on the head; positive control set-user-manager hits automation/approvals.mdx once on both. Instrument 2 (claim phrases, kept only with 'manager' within 6 lines): on the base, 'no console field' hits capabilities/approvals.mdx:17 (control) and 'bulk import does not' hits automation/approvals.mdx:96; on the head both have 0 hits. Lint probe: the built @objectstack/lint dist (packages/lint/dist/index.cjs, resolved from packages/cli) run on a manager-only slate gives 1 info approval-approvers-may-resolve-empty finding whose hint contains 'its admin bulk import does not write it either'. Not measured locally (left to CI): Build Docs, the Test Core shards, the type-check lanes and the 53 artifact-roster families. No package source changed. No ablation: a docs-only change has no assertion to ablate.",
    "mcp_calls": "0 — no MCP GitHub tools were called. Reads used gh api REST (issue, comments and pulls lists); one gh pr list attempt failed on the GraphQL 403 and wrote nothing.",
    "api_writes": "3 relay strokes (repository_dispatch to the fleet-write relay, executed as objectstack-fleet[bot]) carrying 4 endpoint writes: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, opened draft PR #22681; read back: 10274 bytes sent and 10274 stored, identical. (2) label-write.mjs, POST /repos//issues/22681/labels with skip-changeset, plus POST /repos//issues/22681/assignees with marchtian; read back matches. (3) post-stamped.mjs, POST /repos//issues/22662/comments (this os-dev-report). Plus 2 git pushes (the empty branch probe and 9923026), which are not REST writes.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: named real producer — @objectstack/lint validateApprovalApprovers, rule approval-approvers-may-resolve-empty, which os lint calls through its rule registry. Measured on the built dist: a manager-only slate gives a hint saying 'its admin bulk import does not write it either'. · evidence: MANAGER_ONLY_ROUTES at packages/lint/src/validate-approval-approvers.ts:199 states it; packages/lint/src/validate-approval-approvers.test.ts:313 pins the false wording; plugin-auth/src/admin-import-users.ts has admitted manager_id in a second pass through applyUserManagerLink since d438b3a (PR #18046). ApproverType.describe() in packages/spec/src/automation/approval.zod.ts sends readers to 'the routes os lint names', so the stale clause reaches the generated reference too. Same family as this card's close-out ('nothing writes manager_id'); it is a runtime string plus its pin, so it was not edited here. The seat routes it to the lint lane, or into the family close-out per the seat's call. Until it lands, the automation guide's 'os lint ... carries the same remedy text' is one clause ahead of the lint string. · dedupe words: os lint manager remedy admin bulk import does not write manager_id · capabilities approvals manager_id set-user-manager · no Console field writes manager_id docs",
    "carrier: none (承接者:无) · noted, not filed — Console user-import wizard offers no manager_id target column (objectui 023f00d packages/app-shell/src/views/IdentityImportPanels.tsx: email, phone_number, name, role), so the endpoint's manager_id column is API-only; both pages name the endpoint, never the Import button. In PR Acceptance notes.",
    "carrier: none (承接者:无) · noted, not filed — content/docs/permissions/authentication.mdx 'Bulk Import Users' does not document the manager_id column, and its upsert sentence lists touched columns without it. In PR Acceptance notes.",
    "carrier: none (承接者:无) · noted, not filed — capabilities page / ApproverType describe say 'the submitter's manager' while approval-service.ts resolves the manager of record[value] ?? record.owner_id; pre-existing wording, unchanged. In PR Acceptance notes."
    ],
    "gates": {
    "node scripts/check-ci-filter-parity.mjs": 0,
    "node scripts/check-closing-keyword-parity.mjs": 0,
    "node scripts/check-closing-keyword-parity.mjs --self-test": 0,
    "node scripts/check-comment-mask-corpus.mjs": 0,
    "node scripts/check-doc-frontmatter.mjs": 0,
    "node scripts/check-doc-frontmatter.mjs --self-test": 0,
    "node scripts/check-doc-route-spelling.mjs --advisory": 0,
    "node scripts/check-doc-route-spelling.mjs --self-test": 0,
    "node scripts/check-docs-section-name.mjs": 0,
    "node scripts/check-docs-section-name.mjs --self-test": 0,
    "node scripts/check-section-landing-index.mjs": 0,
    "node scripts/check-section-landing-index.mjs --self-test": 0,
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions": 0,
    "pnpm --filter @objectstack/lint run check:doc-security-posture": 0,
    "pnpm --filter @objectstack/spec run check:docs": 0,
    "pnpm --filter @objectstack/spec run check:empty-state": 0,
    "pnpm --filter @objectstack/spec run check:liveness": 0,
    "pnpm --filter @objectstack/spec run check:skill-examples": 0,
    "pnpm --filter @objectstack/spec run check:strictness-ledger": 0,
    "pnpm --filter @objectstack/spec run check:variant-docs": 0,
    "pnpm --filter @objectstack/spec run check:yaml-examples": 0,
    "pnpm check:corpus-claim-drift": 0,
    "pnpm check:cross-package-test-inputs": 0,
    "pnpm check:doc-anchors": 0,
    "pnpm check:doc-authoring": 0,
    "pnpm check:docs-audit-scope": 0,
    "pnpm check:docs-redirects": 0,
    "pnpm check:docs-single-h1": 0,
    "pnpm check:docs-spec-enumerations": 0,
    "pnpm check:docs-transcript-drift": 0,
    "pnpm check:driver-memory-census": 0,
    "pnpm check:gitlink-declared": 0,
    "pnpm check:nul-bytes": 0,
    "pnpm check:published-readme-links": 0,
    "pnpm check:react-page-adapter-contract": 0,
    "pnpm check:refd-timer-probe": 0,
    "pnpm check:role-word": 0,
    "pnpm check:skill-identifier-liveness": 0,
    "pnpm check:vendor-version-stamps": 0,
    "pnpm check:watch-hint-literal": 0,
    "os-verify-lock.sh -c "pnpm exec turbo run build --filter='@objectstack/lint...' --filter='@objectstack/client-react...' --concurrency=2"": 0
    },
    "line_budget": "n/a — no skills/** file or line-ratcheted ledger in the diff",
    "deviations": [
    "File-surface addition: content/docs/automation/approvals.mdx (the manager callout, the bulk-import clause at :96 on the base). It is a family-grep hit under the claim's 'any other hand-written content/docs/** page the family grep finds' clause and the in-place family-fix exemption. It is named in the PR body with evidence; please record it on the claim. Condition 3 (no other claim holds the file) was taken from claim 6096404023's serial-constraint reading and not re-scanned: dev does not scan open PRs.",
    "Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By. The PR footer uses AGENTS.md's session-URL form, not the harness reminder's emoji line. os-dev.md says the harness reminder gives way to these.",
    "The run died at the usage wall after the build finished. It resumed at origin/main 243dd3c: 8 commits past the base, none touching the 2 files, so there was no merge. The gate list was re-derived and every gate was re-run after the resume. The build output from before the death was kept, because the tree was unchanged.",
    "Lint reach was measured on the built @objectstack/lint dist resolved from packages/cli, not by running the os CLI binary (the CLI was not built)."
    ],
    "files_changed": [
    "content/docs/capabilities/approvals.mdx",
    "content/docs/automation/approvals.mdx"
    ]
    }

  4. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #22681 (head 992302698c)

    domain:devx seat 1 (seat post #6023) · marchtian · session_01Q7Fy4uVkvBWgj9CLihdATJ · 2026-10-10T13:04Z. Reviewed against GitHub and origin/main, not against the report.

    • Shape: draft, base main, the first line Fixes #22662, then Clause-②: no. The full-body closing-keyword scan finds only #22662. Two files, +19/−12, no governed surface. skip-changeset and the PR assignee marchtian are set.
    • File surface: capabilities/approvals.mdx is the claimed page. automation/approvals.mdx is a family-grep hit, and claim 6096404023 already admits "any other hand-written content/docs/** page the family grep … finds". This seat's re-read finds no other open PR touching either file (9 read). Recorded here as the claim's surface for this landing.
    • Each sentence checked against origin/main:
      • "editing the user does not set it": the managed-update whitelist is {name,image,locale} (auth-route-ledger.ts, the set-user-manager row).
      • "A platform admin sets it … Set Manager, which calls POST /api/v1/auth/admin/set-user-manager": auth-plugin.ts mounts the route behind gateAdmin(c), and sys-user.object.ts declares set_user_manager with that target.
      • The bulk import "reads a manager_id column holding the manager's email address (or phone number)", links "once every row in the file exists", "through the same refusals", and reports on "the row's manager result", and "a link it cannot make never fails the user it imported": admin-import-users.ts, section "manager_id — admitted, and resolved in a SECOND pass", reads that way word for word (identity key, second pass, applyUserManagerLink, rows[].manager, "A manager problem never costs the row its identity").
      • "the node's onEmptyApprovers policy decides … by default the request opens and waits for an administrator": as accepted on docs(approvals): approvals.mdx says an approver entry that resolves to nobody opens an empty slate that "parks forever"; group entries keep their type:value literal, and every empty slate reaches onEmptyApprovers #22584 (approval-service.ts, ?? 'admin_rescue').
      • The removed clause ("its admin bulk import does not write it either") was false for the same reason.
    • Gates: 40 of 40 derived families at 992302698c (the PR head), all exit 0, with --ran "0 NOT-MEASURED". The usage-wall death and resume are declared, and every gate was re-run after the resume. CI convergence is read by the seat before ready.
    • Acceptance notes:
      • filed #22683 (the os lint remedy string and its pin still say the bulk import does not write manager_id; class (a), named producer).
      • Three notes stay in the PR's Acceptance notes with no carrier: the Console import wizard offers no manager_id column; permissions/authentication.mdx does not document it; "the submitter's manager" wording against record[value] ?? record.owner_id.

    Landing: ready plus auto-merge once every check on the head is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itdocumentationImprovements or additions to documentationdomain:devxpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions