Skip to content

docs(deployment): name both Connect-an-Agent doors in the OS_MCP_STDIO_API_KEY row - #18959

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-18143-connect-agent-env-var-row
Sep 18, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-18143-connect-agent-env-var-row

Conversation

@os-try-charles

@os-try-charles os-try-charles commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #18143

Clause-②: no

The remainder — one line, one file

This card named four sites. PR #18573 landed three of them; content/docs/ai/connect-mcp.mdx belongs to #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 #16746 (decision batch #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 #18142 and PR #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 #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 #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/specdist, 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 from0, Account → Developer0; positive control objectstack1971 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


Generated by Claude Code

…O_API_KEY row

The row told the reader to "Mint one from Setup -> Connect an Agent". SETUP_APP
declares requiredPermissions: ['setup.access'], so a permissionless principal gets
403 PERMISSION_DENIED on /api/v1/meta/apps/setup -- a direct minting instruction that
names only the Setup door sends a non-admin down a path they cannot take. The page is
delivered to them through a navigationContributions entry in the `account` app
instead, and the Setup entry stays for admins deliberately.

Name both doors, in the wording the sibling pages already use: Account -> Developer
for any signed-in user, Setup -> Connect an Agent for platform admins. Compressed to
one table cell; pipes and row count unchanged.

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 18, 2026 — with Claude
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Sep 18, 2026
@os-try-charles
os-try-charles marked this pull request as ready for review September 18, 2026 07:55
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit e19ae67 Sep 18, 2026
45 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-18143-connect-agent-env-var-row branch September 18, 2026 08:11
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/xs 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.

Four more shipped docs pages still send a non-admin to "Setup → Connect an Agent", the one app that 403s for them

2 participants