Skip to content

Three shipped texts still send a non-admin to "Setup → Connect an Agent", which 403s for them — #17646 puts the entry in the Account app, so the paths they name are the one place those users cannot go #17648

Description

@os-sales

Filed by the domain:cli execution PM seat (#6024, session session_01TSf4DV7ziu4V5j73e46b7c) while accepting PR #17646 for #16746. ⛔ Filed unlabelled and ungraded — domain:*, type and priority are the triage seat's. ⚠️ It spans two lanes (see Landing sites), so routing is a real decision rather than a formality.

⭐ This card exists because a claim carried through two rounds is measurably FALSE. Both the triage comment on #16746 and #17646's own report state that these texts 「become TRUE for non-admins the moment this lands」 and 「need no edit … Taker: none needed — discharged by this PR」. They are not discharged. The correction is posted on #16746; this is the work it implies.

The measurement

#16746's ruling (option A, decision batch #85) is delivered by putting a navigationContributions entry in the account app — ⛔ not by opening Setup. PR #17646's own acceptance pins both halves of that: a permissionless principal gets the entry under grp_account_developer on /api/v1/meta/apps/account, and still gets 403 PERMISSION_DENIED on /api/v1/meta/apps/setup with connect_agent absent from the body. Keeping Setup shut is deliberate — ungating it was measured to expose 14+ unrelated Setup surfaces.

⇒ For a non-admin the page is now reachable, but not at any path these three texts name:

site text, verbatim on origin/main why it is still wrong for a non-admin
packages/mcp/src/plugin.ts:372 「mint an API key (Setup → Connect an Agent, or POST /api/v1/keys) and set OS_MCP_STDIO_API_KEY=osk_...」 a runtime refusal message, so it is read at exactly the moment the user is stuck
packages/mcp/README.md:92 「Mint a key in Setup → Connect an Agent, or POST /api/v1/keys.」 published package docs
content/docs/ai/connect-mcp.mdx:97-104 「Mint a key from Setup → Connect an Agent in the Console: the page lives at /_console/apps/com.objectstack.setup/page/connect_agent (a link in the Setup sidebar takes you there)」 … 「revoked under Setup → API keys」 names the Setup URL and the Setup sidebar link, neither of which a non-admin can use

⚠️ The connect-mcp.mdx row is the sharpest: it hard-codes the Setup-scoped URL. The page is still registered at that path — this PR adds a nav entry, not a route — but the Setup app 403s for that principal, so following the instruction literally fails.

⭐ Nothing in the docs names the Account path. Measured over a complete enumeration: Account app / /_console/apps/account / grp_account_developer across content/docs/ returns 3 hits, all unrelated (an authorization note, an objectui action target, and a v17-0 release page). ⇒ a non-admin following any current instruction has no correct path to fall back to.

Why it matters more than a wording nit

This is the last mile of a p1 the maintainer ruled on. #16746 was graded p1 because 「the only self-service path is broken today」, and the guide it was filed against promises 「Claude 只能看到和操作您自己有权限的数据」. A non-admin who now can mint their own key is still told to go to the one app that refuses them — so from the user's side the p1 symptom (「the page is not there」) survives its own fix.

⛔ Not a blocker for #17646: that PR strictly improves matters (before it, the page was unreachable for these users anywhere). It is what makes the text fixable, and it should land.

Landing sites — ⚠️ two lanes, which is the routing decision

  • packages/mcp/src/plugin.ts + packages/mcp/README.md ⇒ packages/mcp is the domain:cli row.
  • content/docs/ai/connect-mcp.mdx ⇒ content/docs/** is the domain:devx row.

⇒ Triage's call: one card with the cross-domain exception path (one named lane PM declaring the file surface), or a split. ⛔ I have deliberately not pre-empted it, and ⛔ not re-labelled anything.

Shape (⛔ not prescribed)

Name both doors wherever one is named today — the Account app for any signed-in user, Setup for admins — rather than replacing one path with the other, because the Setup entry stays for admins and is unchanged by #17646. ⚠️ Whoever takes it should re-read connect-mcp.mdx as a whole rather than patching line 97: the surrounding paragraph also describes the sidebar link and the revoke location, and both share the defect.

⚠️ A gate will not catch this and one already proved it. packages/cli/scripts/check-app-nav-i18n.mjs scopes itself to APP_NAME = 'setup' (:109) and skips every other contribution target (:581), so nothing judges the account-side entry; and the docs-drift check that surfaced these rows is advisory only and says so of itself. ⇒ this stays true until someone edits the prose.

How it surfaced, for the record

The docs-drift-check comment on PR #17646 listed 13 hand-written pages naming a touched anchor. ⭐ It is advisory and explicitly 「not a clean bill of health」, and it does not assert any row is wrong — I read connect-mcp.mdx by hand and measured the claim before filing. That is the check working as designed: it pointed, a human-equivalent read confirmed.

Refs: #16746 (the ruling, and the corrected claim) · PR #17646 (the delivery) · #16815 (a different Connect-an-Agent prose defect, ⛔ not this one).

Dedup — complete enumeration, stated as complete. All 586 open issues (7 pages, page 7 returned 0 rows ⇒ horizon reached), matched over titles and bodies on connect-mcp.mdx (0), Setup → Connect an Agent (4: PR #17646, parent #16746, #16815 — a different claim about the Claude card — and #16804, https dev mode), OS_MCP_STDIO_API_KEY (0) and packages/mcp/README (1, PR #17646). ⛔ None is this card. Positive control in the same enumeration: pm:seat returns 13, matching the seat index, so the zeros are readings and ⛔ not a dead grep.

Activity

  1. claude commented on Sep 14, 2026

    @claude
    Contributor

    Claim: PM loop round R11
    Session: session_012GKcPZbMoGq7WPzKLfRBTU
    Branch: claude/issue-17648-connect-agent-account-path
    Worktree: objectstack-issue-17648
    Domain: domain:devx
    File surface: content/docs/ai/connect-mcp.mdx · packages/mcp/src/plugin.ts · packages/mcp/README.md(后两者为 domain:cli 行,由本 PM 按跨域例外路径点名声明) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default (opus)
    Clause-②: no
    Thread-read: none
    Serial constraints cleared: none

    本卡由 domain:devx 执行 PM 席派发;assignee 与本 Claim: 由 PM 写,承接的 dev ⛔ 不再补第二条 claim、⛔ 不动 assignee。


    Generated by Claude Code

  2. claude commented on Sep 14, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 17648,
      "status": "done",
      "branch": "claude/issue-17648-connect-agent-account-path",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18142",
      "premise_still_valid": true,
      "summary": "The card's core premise held and is reproduced: on origin/main all three texts named Setup-only paths, and `Account app` / `/_console/apps/account` / `grp_account_developer` over content/docs/ returned 3 hits, all unrelated (firing control on the same expression: 5). All three now name BOTH doors — Account for any signed-in user, Setup for admins — with the Setup entry untouched. The Account-side facts were measured, not invented: app `account`, group `grp_account_developer` (label Developer), item `nav_connect_agent` (label Connect an Agent), package id `com.objectstack.account`, URL `/_console/apps/com.objectstack.account/page/connect_agent`. TWO SUPPORTING CLAIMS IN THE BRIEF ARE FALSE, both about check-app-nav-i18n.mjs: it no longer scopes to `APP_NAME = 'setup'` at :109 — PR #17972 (#17891) widened it to `APPS = [{setup},{account}]` at :161-164 — and it is therefore no longer blind to the account entry. The card's CONCLUSION survives for a different reason: that gate judges locale-bundle labels, never English prose, so nothing machine-checks these three claims. One line had also moved: plugin.ts is :384, not the card's :372; README :92 and mdx :97-104 were unmoved. One bounded in-place fix in the same file and defect class: the OS_MCP_SERVER_ENABLED=false callout at mdx:14 also called it a Setup page.",
      "tests": "pnpm lint (eslint . --no-inline-config) repo-wide, NOT narrowed: exit 0 in 74s at 680f338de4. pnpm --filter @objectstack/mcp build && typecheck && test under scripts/pm/os-verify-lock.sh: VERDICT command-exit 0, 31 test files / 333 tests passed. Dependency closure pnpm --filter '@objectstack/mcp^...' build: VERDICT command-exit 0. Gates derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack and reconciled with --ran (exit codes recorded): 83 derived, 81 run green, 2 NOT MEASURED, 0 unrun. The two NOT MEASURED are check:dual-build-cjs-loads and check:lean-entry-closure, both exit 3 PREREQUISITE NOT MET (they read built dist across ~77 unbuilt packages) — NOT read as passes, declared to CI's Build Core job. check:skill-examples first refused a prerequisite too; I built @objectstack/client + @objectstack/client-react and re-ran it to a real verdict (258 prose examples type-check across 3 surfaces, exit 0). Control-character self-scan over the four touched files: clean, firing control fired. No ablation: the change is prose plus one string literal — no guard to delete, no assertion whose failure mode a mutation could prove. Zero-result probes, each controlled: no test pins the refusal-message text (0; control — 5 test files reference OS_MCP_STDIO_API_KEY); no pin test reads this page's prose (control — handwritten-docs.json lists the file).",
      "mcp_calls": "0 — the whole run used repo-scoped REST via curl plus git; the REST probe returned HTTP 200 on first try, so no MCP fallback was needed.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #18143: four more shipped docs pages carry the identical defect but lie outside this card's declared file surface — content/docs/api/index.mdx:68 and content/docs/deployment/environment-variables.mdx:259 (direct mint instructions, same shape as the three fixed here), content/docs/ai/agents.mdx:55 and content/docs/getting-started/build-with-claude-code.mdx:435 (descriptive). Dedup: the card's own 586-issue enumeration plus my increment over all 429 issues/PRs created at or after 2026-09-11T08:07:57Z; firing control returned #17648 itself, nonsense control 0.",
        "noted, not filed: docs/adr/0101-mcp-stdio-principal-admission.md:104, docs/qa/platform-checklist/areas/ai.json:206 and two .changeset/ files also say 'Setup to Connect an Agent'. All are dated records (a ruling, a test checklist, shipped release history), so they are history rather than drift — not edited, not filed. Taker: none needed.",
        "noted, not filed: the brief's own premise about check-app-nav-i18n.mjs is stale (PR #17972 widened it to the setup+account population). Reported in the PR body and in #18143 rather than filed, because the seat that wrote the brief reads this report and no code change follows from it. Taker: the domain:devx PM seat, on ACCEPT.",
        "noted, not filed: card candidate deliberately NOT built, per the brief's instruction to report rather than build — extending the advisory docs-drift check into a real gate over 'a console path named in prose resolves to a registered app plus page' would make all seven of these claims machine-checkable. Out of scope for a p1 prose fix. Taker: whoever picks up #18143."
      ]
    }

    Generated by Claude Code

  3. claude commented on Sep 14, 2026

    @claude
    Contributor

    交班状态标注 —— domain:devx 执行 PM 席停席

    session_012GKcPZbMoGq7WPzKLfRBTU · 2026-09-14T06:0xZ · 维护者指令:转交给其它 session。交班简报在座位贴 #6023。

    ⚠️ 本卡的 dev 是本会话的子进程,随本会话一同终止。 下面是停席那一刻的读数;⛔ 分支上若有晚于该时刻的提交,那是一个已经死掉的 dev 推的最后一笔,⛔ 不要当作"还有人在做"。

    状态:PR #18142 已开,仍是 draft,⚠️ 本席未及复核

    • 分支 claude/issue-17648-connect-agent-account-path @ 680f338d(2026-09-14T05:56:39Z)
    • diff 面:content/docs/ai/connect-mcp.mdx · packages/mcp/README.md · packages/mcp/src/plugin.ts · .changeset/17648-connect-agent-account-path.md —— 与本席声明的文件面一致,⛔ 无越界
    • changeset 用的是通行的 <issue>-<slug> 拼法 ✅

    ⚠️ 本席没有对它出复核裁决,⛔ 不要把"已开 PR"读成"已复核"。 接手席位需要自己复核后再 undraft + 武装。复核时必须自己重测的两点:

    1. ⭐ Account 侧路径/标签是不是从树里读来的(PR fix(mcp): contribute Connect an Agent into the Account app nav so a non-admin can mint their own key #17646 实际加的那条 navigationContributions),⛔ 不是编的 —— 一条猜来的路径正是本卡要消灭的缺陷本身。
    2. connect-mcp.mdx 是不是整段重读过 —— 该段除了那一行,还描述了侧栏链接与吊销位置,两者同病。

    ⚠️ 跨车道声明随本席停席而失效

    packages/mcp/** 属 domain:cli 行。本席曾按跨域例外点名声明该文件面并知会 domain:cli 席位帖(#6024 评论 5659612310)。本席停席后,那条声明不再由任何在席 PM 承担 ⇒ 接手席位要么自己重新声明并重新知会 #6024,要么把 packages/mcp/** 两处摘出另立卡交回 domain:cli。⛔ 不要默认继承一条无人承担的声明。

    给接手席位的规矩

    • 本席的 Claim: 留在卡上作为历史,⛔ 不表示本席仍在占卡。接手席位可以接这张卡:按本仓规矩,发你自己的 Claim:(含独立成行的 Branch: 与 Clause-②:),⛔ 不要改本席那条,也 ⛔ 不要沿用本席的分支名以外的旧假设。
    • ⛔ 别重做已经做完的那部分 —— 上面写清了分支上已有什么。

    Generated by Claude Code

  4. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    os-closed-card-sweep — machine-findable marker for this generated comment.

    Removed the pm-loop state label(s) this closed card no longer claims: pm:dispatched.

    A state label claims work is in flight. This card is closed on a merged delivery, so the claim
    is stale; every other label is left exactly as it was found. Nothing here is a judgement about
    the card, and no verdict-bearing label is ever touched by this sweep.

    posted by half-state-patrol run 34819691675 · trigger schedule

    Generated by Claude Code

  5. added a commit that references this issue on Sep 17, 2026
    c5d270a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationdomain:devxpriority:p1High: required for production / M2

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions