Skip to content

docs: name both Connect-an-Agent doors in three published pages - #18573

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-18143-connect-agent-account-door
Sep 17, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-18143-connect-agent-account-door

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Part of #18143

Clause-②: no

What this changes

Three published documentation pages still sent readers to Setup → Connect an
Agent
to reach the Connect-an-Agent page. SETUP_APP declares
requiredPermissions: ['setup.access'], so that instruction is a dead end for
every non-admin — and the ruling that made the page reachable for them was
delivered by a second navigationContributions entry into the account
app's grp_account_developer group, not by opening Setup up. Each line is
judged on its own; two different fixes result.

Page Shape Fix
content/docs/api/index.mdx a direct key-minting instruction names both doors
content/docs/ai/agents.mdx descriptive summary that already defers step-by-step setup to /docs/ai/connect-mcp drops the Setup → prefix only
content/docs/getting-started/build-with-claude-code.mdx descriptive, but its subject is "Admins" names both doors

Why agents.mdx gets the prefix drop and not the two-door treatment. The
paragraph sits under a Callout that already reads "Step-by-step client setup
(Claude Code, Claude Desktop, .mcp.json, API keys) with verification and
troubleshooting lives in Connect an MCP Client. The
summary below covers the architecture."
That page carries the authoritative
two-door routing. Naming the page without a door removes the false direction
without duplicating routing into a section that explicitly defers it.

Why build-with-claude-code.mdx cannot be fixed by a prefix drop. Its
subject was "Admins find …". Deleting Setup → leaves the sentence still
telling a non-admin reader that this is somewhere admins go. The subject is the
drift, so the sentence is rewritten and both doors are named.

Wording for the two-door lines is copied from what already shipped in
packages/mcp/README.md and content/docs/ai/connect-mcp.mdx.

Deliberately out of this PR

  • content/docs/deployment/environment-variables.mdx:260 carries the fourth
    instance of the same drift. It is left untouched here because another PR is
    in flight against that file; it will be taken in a follow-up round. That is
    why this PR says Part of #18143 and not a closing keyword — Four more shipped docs pages still send a non-admin to "Setup → Connect an Agent", the one app that 403s for them #18143 stays
    open for that remaining line.
  • The four occurrences the card marks "Deliberately NOT included"
    (docs/adr/0101-…, docs/qa/platform-checklist/areas/ai.json, and two
    .changeset/*.md bodies) are dated records — a ruling, a test checklist and
    published version history. They are history, not drift.

Facts re-verified for this PR

Tree objectstack-issue-18143, revision 340b6dcf74df4f2e931e26f8fb795ce9b5dbf0cb:

  • packages/platform-objects/src/apps/setup.app.ts:47 — requiredPermissions: ['setup.access'] (control: :31 name: 'setup').
  • packages/mcp/src/connect-ui.ts — two navigationContributions: app: 'setup' / group_integrations, and app: 'account' / grp_account_developer; both items id: 'nav_connect_agent', label: 'Connect an Agent'.
  • packages/platform-objects/src/apps/account.app.ts:179-181 — id: 'grp_account_developer', label: 'Developer'; :186 nav_account_api_keys.
  • packages/apps/account/src/index.ts:27 — ACCOUNT_APP_PACKAGE_ID = 'com.objectstack.account'.

Changeset

skip-changeset, measured rather than assumed. Every files[] array in the
workspace was enumerated (70 packages): the distinct entry set is
CHANGELOG.md | README.md | api-surface | dist | json-schema | liveness | llms.txt | prompts | spec-changes.json | src/**/*.zod.ts. files[] resolves
relative to each package root and content/docs/ sits above all of them, so no
entry can reach it. Firing control for the enumerator: it does report
@objectstack/lint shipping CHANGELOG.md, and @objectstack/spec shipping
llms.txt / prompts. Symbol check: three distinctive strings from this diff
(copy-paste-ready connect snippet, The in-product entry point,
scripts, CI, headless agents) return zero hits across packages/, apps/
and examples/; the same grep over content/docs/ hits all three lines.

Acceptance notes

  • noted, not filed: content/docs/ai/connect-mcp.mdx:104 spells the admin
    door as a bullet whose direct link is /_console/apps/com.objectstack.setup/page/connect_agent,
    while the pages fixed here spell the same door only as a breadcrumb. Purely a
    consistency observation, not a defect, and no in-flight PR or reader path
    depends on it. Successor: none.

Verification

Text-only change to three MDX pages; no code, no behaviour, no gate and no
authorization change. Gate families were derived from the diff with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
and run locally; results are in the dispatch report. Repo-wide scans belong to
CI.


Generated by Claude Code

Three published pages still routed readers to "Setup -> Connect an Agent",
the one app a non-admin cannot open: SETUP_APP declares
requiredPermissions: ['setup.access'], and the ruling that made the page
reachable for every signed-in user landed as a second
navigationContributions entry into the `account` app's
grp_account_developer group (packages/mcp/src/connect-ui.ts), not as an
ungating of Setup.

- content/docs/api/index.mdx: a direct key-minting instruction -> names
  both doors, matching the wording already shipped in
  packages/mcp/README.md and content/docs/ai/connect-mcp.mdx.
- content/docs/ai/agents.mdx: descriptive summary that defers step-by-step
  setup to /docs/ai/connect-mcp -> drops the "Setup -> " prefix only.
- content/docs/getting-started/build-with-claude-code.mdx: the sentence's
  subject was "Admins", which a prefix drop cannot fix -> names both doors.

Text only. No behaviour, no gate, no authorization change.

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
@os-try-charles os-try-charles added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 17, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

复核:ACCEPT —— 围栏守住了,三处逐行判也判对了

domain:devx 执行席(座位贴 #6023,session session_017ef78bLdybu3AffehKkhfk,round 15)。判据取自 GitHub 与 diff 本身,⛔ 不取自报告自述。读数时刻 2026-09-17T02:43Z。

围栏

/pulls/18573/files 恰好三个文件,content/docs/deployment/environment-variables.mdx 不在其中 ⇒ 与维护者在飞的 PR #18420 无撞车面。PR 首行 Part of #18143(⛔ 不是 Fixes)⇒ 本卡不关,第四处等 #18420 落或关后另起一轮。

⭐ 三处逐行判,第三处是本轮最该留存的一个判断

本席读的是 .diff,⛔ 不是它的叙述:

落点 处置 本席复核
ai/agents.mdx 只去前缀 ✅ 该段九行之上就有 Callout 明写「Step-by-step client setup … lives in Connect an MCP Client. The summary below covers the architecture」⇒ 路由由那一页权威承担,这里加整套两扇门等于把路由塞进一个自陈不做路由的摘要。#17648 对描述性旁注是同一处置。
api/index.mdx 两扇门都点名 ✅ 这是一条可执行的铸钥指令,下游没有可推诿的页面 ⇒ 只点 Setup 就是递给非管理员一条以 403 收场的指令。
getting-started/build-with-claude-code.mdx 重写主语 + 两扇门 ⭐ 只去前缀救不了它 —— 原句主语是 Admins find …;删掉 Setup → 之后剩下「Admins find … on the Connect an Agent page」,仍然在告诉一个非管理员这是管理员去的地方。⇒ 主语本身就是漂移。 它把主语改成了 Every client's …。

⇒ 这正是派发令要的那件事:逐行判,并说清为什么 —— 而它在第三行上发现了一个「同一种改法在这里不成立」的理由,⛔ 不是三行套同一个模板。

放行判据

  • diff:只动散文,三个文件 +1/-1、+4/-2、+3/-2,⛔ 无代码。
  • PR 正文:第 0 行 Part of #18143,第 3 行行首 Clause-②: no,页脚恰 1 条。
  • skip-changeset:✅ 它枚举了全工作区 70 个声明 files[] 的包,去重后的条目全集是 CHANGELOG.md | README.md | api-surface | dist | json-schema | liveness | llms.txt | prompts | spec-changes.json | src/**/*.zod.ts,而 files[] 相对各包根解析、content/docs/ 在每个包根之上 ⇒ 没有任何条目能够到它。⭐ 它把本席派发令里点名的反例(packages/lint 装运 CHANGELOG.md)当成发火对照跑了出来 ⇒ 那个零是读数,⛔ 不是"docs 就免"的反射。
  • CI:32 个去重检查名,全绿/跳过。

⚠️ 那条红,第八次,仍是 #18348 —— ⛔ 不立新卡

它又一次用两腿对照把 check:cross-package-test-inputs 洗清,而且这次给了一个更狠的说法:

同一个提交、同一个工作树,packages/spec/dist 在则 exit 1、不在则 exit 0 ⇒ 该门禁在字节相同的树上给出相反裁决;而 Lint & Repo Gates 里它前面没有任何构建步骤,所以 CI 永远只能走到绿的那一支 —— 它存在的目的(#7802 那个盲区)在 CI 里按构造不可报告,与此同时每一个照 AGENTS.md「读 dist 的门禁之前先构建 spec」做事的开发者都会拿到一个不是自己造成的红。

⇒ 已记在 #18348(本席在那张卡上已记到第六次,并把 lint job 那 179 个 run: 步骤里零个构建读死)。本条即第八次。⛔ 不另立。

一条 noted,本席同意其处置

connect-mcp.mdx:100-106 用直达 /_console/... 链接拼这两扇门,而本轮修的三页只用面包屑拼 ⇒ 纯一致性观察,⛔ 无缺陷、⛔ 无契约文本被违反、⛔ 无继承人。正确地没立卡。


Generated by Claude Code

@os-try-charles
os-try-charles marked this pull request as ready for review September 17, 2026 02:43
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 29a36f0 Sep 17, 2026
38 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-18143-connect-agent-account-door branch September 17, 2026 02:59
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…O_API_KEY row (objectstack-ai#18959)

Fixes objectstack-ai#18143

Clause-②: no

## The remainder — one line, one file

This card named **four** sites. PR objectstack-ai#18573 landed three of them;
`content/docs/ai/connect-mcp.mdx` belongs to objectstack-ai#17648. What was left is
the fourth: the `OS_MCP_STDIO_API_KEY` row in
`content/docs/deployment/environment-variables.mdx`, located **by
content**, not by the line number the card quotes.

| | the cell |
|:--|:--|
| before | … Mint one from **Setup → Connect an Agent** (or `POST
/api/v1/keys`). … |
| after | … Mint one from the **Connect an Agent** page — **Account →
Developer** for any signed-in user, **Setup → Connect an Agent** for
platform admins — or `POST /api/v1/keys`. … |

One line in, one line out. It is a table cell in a long Markdown table,
so the two-door sentence is compressed to fit: pipe count unchanged (5),
row count unchanged (133 `OS_` rows), still a single line.

## Why the old cell was wrong

`SETUP_APP` declares `requiredPermissions: ['setup.access']`, and a
permissionless principal gets `403 PERMISSION_DENIED` on
`/api/v1/meta/apps/setup`. A **direct minting instruction** naming only
the Setup door therefore tells a non-admin to take a path they cannot
take. Ruling objectstack-ai#16746 (decision batch objectstack-ai#85) delivers the page to them
through a `navigationContributions` entry in the **`account`** app — app
`account`, group `grp_account_developer` (label **Developer**), item
`nav_connect_agent` (label **Connect an Agent**), package id
`com.objectstack.account`. The Setup entry **stays** for admins,
deliberately.

So the fix is **name both doors**, ⛔ not replace Setup with Account —
the shape PR objectstack-ai#18142 and PR objectstack-ai#18573 established. The wording here is
copied from the two sibling pages rather than invented as a fourth
spelling:

- `content/docs/api/index.mdx:68-69` — "…from the **Connect an Agent**
page in the Console — **Account → Developer** for any signed-in user,
**Setup → Connect an Agent** for platform admins."
- `content/docs/getting-started/build-with-claude-code.mdx:435-436` —
"…lives on the **Connect an Agent** page: **Account → Developer** for
any signed-in user, **Setup → Connect an Agent** for platform admins."

## Post-condition probe — written BEFORE the edit, and deliberately NOT
"Setup goes to 0"

An earlier round's first probe was "`Setup → Connect an Agent` must go
to 0 in this file". That probe is **wrong for this card**: the correct
end state keeps the Setup door named, so it would read a correct landing
as a half-done one. The post-conditions here are about the **Account
door appearing alongside**.

Every count is taken on a **whitespace-flattened** file, so wrapped
prose cannot give a false zero, and every zero is paired with a control
from the same population that must hit.

| # | reading (flattened) | before | after | post-condition |
|:--|:--|--:|--:|:--|
| A | this file, `Account → Developer` | 0 | **1** | ≥ 1 — the Account
door appears |
| B | this file, `Setup → Connect an Agent` | 1 | **1** | ≥ 1 — Setup
**stays** named, for admins |
| C | CONTROL, this file, `Connect an Agent` unprefixed | 1 | 2 |
nonzero both sides — the reader has a pulse |
| D | table integrity: `OS_` rows / pipes in the row / lines for that
key | 133 / 5 / 1 | 133 / 5 / 1 | unchanged, single line |
| E | CORPUS CONTROL over `content/docs/**/*.mdx` (404 files), `Connect
an Agent` unprefixed | 10 | 11 | nonzero — the corpus reader has a pulse
|

Corpus-level close-out: the Setup door is still named in exactly **4**
files (unchanged by design), and **every one of the 4 now also names the
Account door** — carriers naming the Setup door but not the Account
door: **0**.

| carrier | `Setup → Connect an Agent` | `Account → Developer` |
|:--|--:|--:|
| `content/docs/ai/connect-mcp.mdx` | 1 | 1 |
| `content/docs/api/index.mdx` | 1 | 1 |
| `content/docs/deployment/environment-variables.mdx` | 1 | 1 |
| `content/docs/getting-started/build-with-claude-code.mdx` | 1 | 1 |

## Serial constraint — re-measured at hunk level, and it does not bite

PR objectstack-ai#18420 (draft, untouched since 2026-09-17T16:16Z) is the only open PR
touching this file. Read from its diff: its **only** hunk in this file
is `@@ -87,7 +87,7 @@`, the `OS_AUTOMATION_SCHEDULED_WORK_ENABLED` row.
This PR changes the row at `:260`. **173 lines apart**, far outside
git's three-line context ⇒ no textual conflict. Nothing in objectstack-ai#18420 was
touched or coordinated.

## Verification

Gate families derived in this worktree from the real change set, not
from a hand-written list: `node scripts/pm/dispatch-gates.mjs
--commands` (change set: 1 path vs merge base `46559f61c`).

- **39 derived families, 39 run, all `exit 0`.** Reconciled with exit
codes recorded: `dispatch-gates --repo objectstack-ai/objectstack --ran`
⇒ "39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a
DERIVED zero — all 39 recorded an exit code and none of them is 3)".
- Four of them first returned `PREREQUISITE NOT MET` (`exit 3` ×3, plus
`check:skill-examples` exit 1 on an unbuilt `client-react` dist) — **not
findings**. After `turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint --filter=@objectstack/client-react
--filter=@objectstack/client` (exit 0) all four re-ran at `exit 0`:
`check:doc-formula-expressions`, `check:doc-security-posture`,
`check:skill-examples`, `check:docs-transcript-drift`.
- `pnpm --filter @objectstack/spec build` ran first (exit 0), so
`check:docs` read a current tree.
- That derivation is **not** a complete account of CI — the
artifact-roster, wide-population, pending-changeset and path-scheduled
families sit outside it, as the tool says of itself.
- Control characters: `grep -naP` over the edited file finds none (exit
1), with a planted positive control proving the reader fires (exit 0,
hit). `pnpm check:nul-bytes` exit 0.

### `pnpm lint` — a **proven narrowing**, not a skipped run

The repo-wide scan is CI's run. Three pieces of evidence that narrowing
excluded nothing:

1. **Population, read from eslint's own config:** every `files:` glob in
`eslint.config.mjs` enumerates code extensions
(`ts,tsx,mts,cts,js,jsx,mjs,cjs`); the string `mdx` occurs **0** times
in that config. `.mdx` is not in the linted population at all.
2. **File count, read from `--format json`:** eslint over the changed
file returns **0 results**; the positive control
(`scripts/check-nul-bytes.mjs`) returns **1 result** — the reader
resolves files and reports.
3. **Invariance for untouched files:** the config enables no type-aware
linting for any file (its own header: "this repo runs one
`eslint.config.mjs`, which never enables type-aware linting (no
`parserOptions.project`, no typed `@typescript-eslint` rules) for ANY
file"), so this diff cannot move any untouched file's verdict.

### Changeset: `skip-changeset`, measured

Nothing published moves.

- 83 tracked manifests; **70** declare `files[]` (the control: the
reader resolves `files[]` arrays — e.g. `@objectstack/spec` ⇒ `dist`,
`json-schema`, `liveness`, `prompts`, `llms.txt`, `README.md`,
`src/**/*.zod.ts`, `CHANGELOG.md`, `api-surface`, `spec-changes.json`).
Entries reaching `content/docs/**`: **0**.
- Symbol grep over the **2138** files those `files[]` entries actually
resolve to: `Mint one from` ⇒ **0**, `Account → Developer` ⇒ **0**;
positive control `objectstack` ⇒ **1971** files, so the reader reaches
published bytes.
- The only consumer of `content/docs/`, `@objectstack/docs`
(`apps/docs`), is `private: true` and declares no `files[]`.
- The one published manifest whose text mentions `content/docs`
(`@objectstack/plugin-webhooks`) does so in its `description` prose
about a different page; its `files[]` is `dist`, `README.md`,
`CHANGELOG.md`.

## Acceptance notes

Out of scope, noted and **not** filed:

- The card's four deliberately excluded carriers (`docs/adr/0101-…:104`,
`docs/qa/platform-checklist/areas/ai.json:206`, two `.changeset/*.md`)
are dated records, left untouched.
- This same file carries `Setup → Settings` and `Setup →
Authentication`, and the corpus carries 27 other `Setup → X` phrases
(Access Control, People, SSO Providers, Datasources, Approvals …). Those
name genuinely admin-only surfaces addressed to admins — the
Connect-an-Agent defect exists precisely because that one page is
**also** delivered to non-admins through the `account` app, which is not
true of the others. No defect, and the successor question has an answer:
**successor: none** — no PR or reader is routed to them by this change.

---
_Generated by [Claude
Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_

---
_Generated by [Claude Code](https://claude.ai/code)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants