Repository navigation
Four more shipped docs pages still send a non-admin to "Setup → Connect an Agent", the one app that 403s for them #18143
Description
Filed by the domain:devx dev seat while landing #17648 (PR #18142). ⛔ Filed unlabelled and ungraded — domain:*, type and priority are the triage seat's.
Why this is a separate card
#17648 measured the defect and named three landing sites, and its Claim: declared exactly that file surface: content/docs/ai/connect-mcp.mdx, packages/mcp/src/plugin.ts, packages/mcp/README.md. PR #18142 fixes those three. The pages below carry the identical defect but sit outside that declared surface, so editing them there would have been a file-surface breach. They are the remainder, not a second opinion.
The measurement
#16746's ruling (option A, decision batch #85) is delivered by a navigationContributions entry in the account app (packages/mcp/src/connect-ui.ts), ⛔ not by opening Setup. SETUP_APP still declares requiredPermissions: ['setup.access'] (packages/platform-objects/src/apps/setup.app.ts:47), and PR #17646's acceptance pins that a permissionless principal still gets 403 PERMISSION_DENIED on /api/v1/meta/apps/setup. Keeping Setup shut is deliberate — ungating it was measured to expose 14+ unrelated Setup surfaces.
⇒ every text below names a path that principal cannot take. Measured on origin/main at a90a9f267, located by content:
| site | text | shape |
|---|---|---|
content/docs/api/index.mdx:68 |
"(the key is shown once), or from Setup → Connect an Agent in the Console." | a direct mint instruction — same shape as the three #17648 fixed |
content/docs/deployment/environment-variables.mdx:259 |
"Mint one from Setup → Connect an Agent (or POST /api/v1/keys)." |
a direct mint instruction, in the OS_MCP_STDIO_API_KEY row |
content/docs/ai/agents.mdx:55 |
"Setup → Connect an Agent page: per-client connect snippets, the portable …" | descriptive: calls it a Setup page |
content/docs/getting-started/build-with-claude-code.mdx:435 |
"download and API-key minting — on the Setup → Connect an Agent page." | descriptive: calls it a Setup page |
Shape (⛔ not prescribed)
The same as #17648's: name both doors wherever one is named today — the Account app for any signed-in user, Setup for admins — rather than replacing one with the other, because the Setup entry stays for admins and is unchanged by #17646. PR #18142 is the worked precedent, and the Account-side facts it measured are reusable verbatim:
- app
account, groupgrp_account_developer(label Developer), itemnav_connect_agent(label Connect an Agent) —packages/mcp/src/connect-ui.ts,packages/platform-objects/src/apps/account.app.ts, labels inapps/translations/en.ts(all four locales, The contributednav_connect_agententry in the Account app has no translation key in any locale, so the same page renders 「连接智能体」 under Setup and "Connect an Agent" under Account for the same user #17759); - package id
com.objectstack.account(packages/apps/account/src/index.ts), so the console URL is/_console/apps/com.objectstack.account/page/connect_agent; - route
/apps/:appName/page/:pageName, segment resolved_packageIdfirst then appname— objectuipackages/app-shell/src/utils/appRoute.ts.
Setup → prefix may be the whole edit, as it was for #17648's OS_MCP_SERVER_ENABLED=false callout. Whoever takes it should judge per row.
Deliberately NOT included
docs/adr/0101-mcp-stdio-principal-admission.md:104, docs/qa/platform-checklist/areas/ai.json:206, .changeset/16746-connect-agent-account-nav.md:12 and .changeset/oauth-agent-runs-as-the-user.md:12 also carry the phrase. All are dated records — a ruling, a test checklist and shipped release history — so they are history, ⛔ not drift, and ⛔ not part of this card.
A gate will not catch this
packages/cli/scripts/check-app-nav-i18n.mjs judges locale-bundle labels, never English prose in docs — and note that #17648's own brief is stale on this script: PR #17972 (#17891) widened it from setup-only to the declared population APPS = [{ name: 'setup' }, { name: 'account' }] (:161-164). The widening does not reach prose. The docs-drift check that surfaced these rows is advisory only and says so of itself. ⇒ this stays true until someone edits the prose.
Refs: #17648 (the three-site card) · PR #18142 (the fix, and the Account-side measurements) · #16746 (the ruling) · PR #17646 (the delivery) · #16815 (a different Connect-an-Agent prose defect, ⛔ not this one).
Dedup. #17648's own filing enumerated all 586 open issues over titles and bodies on Setup → Connect an Agent → 4 hits (PR #17646, #16746, #16815, #16804), ⛔ none of them this. I re-checked only the increment since that filing: all 429 issues and PRs created at or after 2026-09-11T08:07:57Z (5 REST pages, oldest fetched 2026-09-10T23:01 ⇒ the window is fully covered), matched over titles and bodies. Setup → Connect an Agent → 2: #17648 itself and PR #17972. ⛔ Neither is this card. Firing control: that same expression returning #17648 is the positive control. Nonsense control in the same window: 0.
Generated by Claude Code
Activity
os-try-charles commentedon Sep 17, 2026
PM loop round 15 —⚠️ 四个落点中的一个被串行约束围起来,本轮只派其余三个,用
domain:devx执行席认领本卡。Part of。围栏与它的理由
卡面点名四个落点。本席在派发当刻把 25 个 open PR 的
files逐个读过,读到 #18420 正在改content/docs/deployment/environment-variables.mdx—— 那是维护者自己的 PR。⇒ 同文件在飞,本轮 ⛔ 不碰它,避免与维护者的改动撞车。⇒ 本轮按
Part of #18143落其余三处,⛔ 不用Fixes,本卡不关。等 #18420 落或关之后,余下那一处另起一轮。⭐ 这与本卡自己的来历同形:#17648 的 dev 当初正是因为落点在申报的文件面之外而没有顺手改、另立了本卡 —— 分诊把那件事记为正例。本轮沿用同一条纪律。读数时刻 2026-09-17T02:13Z;树
origin/main=f962be9d08cc3fcd0e016c7617434e85d13fec35。本轮三个落点(卡面原文)
content/docs/api/index.mdx:68content/docs/ai/agents.mdx:55content/docs/getting-started/build-with-claude-code.mdx:435派发口径
Setup →前缀可能就是全部改动(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 对OS_MCP_SERVER_ENABLED=false那条旁注就是这么做的)。⭐ 逐行判,并在报告里写清每一行你选了哪种及理由。account、groupgrp_account_developer(标签 Developer)、itemnav_connect_agent(标签 Connect an Agent),见packages/mcp/src/connect-ui.ts;包 idcom.objectstack.account⇒ 控制台 URL/_console/apps/com.objectstack.account/page/connect_agent。docs/adr/0101-…:104、docs/qa/platform-checklist/areas/ai.json:206、两个.changeset/…)—— 它们是有日期的记录(裁定、测试清单、已发布的版本历史),是历史 ⛔ 不是漂移。Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
os-dev-report
{ "issue": 18143, "session_id": "session_017ef78bLdybu3AffehKkhfk", "status": "done", "branch": "claude/issue-18143-connect-agent-account-door", "pr": "https://github.com/objectstack-ai/objectstack/pull/18573", "pr_number": 18573, "pr_draft": true, "premise_still_valid": true, "tree": "/home/user/objectstack-issue-18143", "base_rev": "340b6dcf74df4f2e931e26f8fb795ce9b5dbf0cb", "head_rev": "ccf23c895278b3dadf7e0b27d3d1508b4414070b", "summary": "Three published pages routed readers to 'Setup -> Connect an Agent', an app that is 403 for every non-admin, while the ruling that made the page reachable for them landed as a second navigationContributions entry into the account app's grp_account_developer group. Each of the three lines was judged on its own: the one direct minting instruction now names both doors, one descriptive line that already defers step-by-step setup to /docs/ai/connect-mcp gets the 'Setup -> ' prefix dropped, and one descriptive line whose subject was 'Admins' is rewritten to name both doors because a prefix drop cannot fix a subject. content/docs/deployment/environment-variables.mdx is deliberately untouched (PR #18420 in flight against it), so the PR says 'Part of #18143' and the card stays open for that fourth line. No code touched.", "fenced_file_untouched": "content/docs/deployment/environment-variables.mdx — verified absent from the diff: `git diff --name-only 340b6dcf7...ccf23c895` returns exactly the three target paths.", "changes": [ { "file": "content/docs/api/index.mdx", "line_at_base": 68, "shape": "direct key-minting instruction", "treatment": "both doors named", "why": "The sentence is an actionable minting instruction with no downstream page to defer to. Naming only Setup hands a non-admin an instruction that ends in 403, so both doors are named, in the wording already shipped by packages/mcp/README.md:92-94 and content/docs/ai/connect-mcp.mdx:100-106.", "before": "- **API key** (scripts, CI, headless agents): mint one with `POST /api/v1/keys`\n (the key is shown once), or from **Setup → Connect an Agent** in the Console.\n Send it as `x-api-key: osk_…` or `Authorization: Bearer osk_…`.", "after": "- **API key** (scripts, CI, headless agents): mint one with `POST /api/v1/keys`\n (the key is shown once), or from the **Connect an Agent** page in the Console\n — **Account → Developer** for any signed-in user, **Setup → Connect an Agent**\n for platform admins. Send it as `x-api-key: osk_…` or\n `Authorization: Bearer osk_…`." }, { "file": "content/docs/ai/agents.mdx", "line_at_base": 55, "shape": "descriptive — names the page as the in-product entry point", "treatment": "prefix drop only (`Setup → ` removed)", "why": "This paragraph sits nine lines 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.' /docs/ai/connect-mcp carries the authoritative two-door routing. So the drift here is exactly the `Setup → ` prefix: removing it makes the sentence true and complete for a section that explicitly defers routing, and adding the full two-door table would duplicate routing into a summary that says it is not doing routing. This is the same disposition #17648 applied to a descriptive aside.", "before": "authentication tracks: The in-product entry point is the\n**Setup → Connect an Agent** page: per-client connect snippets, the portable\nSKILL.md download (`GET /api/v1/mcp/skill`), and API-key minting.", "after": "authentication tracks: The in-product entry point is the\n**Connect an Agent** page: per-client connect snippets, the portable\nSKILL.md download (`GET /api/v1/mcp/skill`), and API-key minting." }, { "file": "content/docs/getting-started/build-with-claude-code.mdx", "line_at_base": 435, "shape": "descriptive — but its SUBJECT is 'Admins'", "treatment": "both doors named (prefix drop would not have been enough)", "why": "Deleting `Setup → ` here leaves 'Admins find every client's copy-paste-ready connect snippet ... on the Connect an Agent page' — still telling a non-admin reader that this is somewhere admins go. The subject IS the drift, so a prefix drop cannot reach it. This is a getting-started tutorial whose next paragraph is about minting a key for headless callers, i.e. a reader who will go looking; the sentence is rewritten and both doors are named.", "before": "Admins find every client's copy-paste-ready connect snippet — plus the SKILL.md\ndownload and API-key minting — on the **Setup → Connect an Agent** page.", "after": "Every client's copy-paste-ready connect snippet — plus the SKILL.md download and\nAPI-key minting — lives on the **Connect an Agent** page: **Account → Developer**\nfor any signed-in user, **Setup → Connect an Agent** for platform admins." } ], "facts_reverified": { "tree": "/home/user/objectstack-issue-18143", "rev": "340b6dcf74df4f2e931e26f8fb795ce9b5dbf0cb", "items": [ "packages/platform-objects/src/apps/setup.app.ts:47 — `requiredPermissions: ['setup.access']` (must-hit control in the same file: `:31` `name: 'setup'`). Setup is still gated; #17646 did not open it.", "packages/mcp/src/connect-ui.ts — TWO navigationContributions: { app: 'setup', group: 'group_integrations', priority: 110 } and { app: 'account', group: 'grp_account_developer', priority: 200 }; both items id `nav_connect_agent`, label `Connect an Agent`, icon `bot`, pageName `connect_agent`.", "packages/platform-objects/src/apps/account.app.ts:179 `id: 'grp_account_developer'`, :181 `label: 'Developer'`, :186 `id: 'nav_account_api_keys'`.", "packages/apps/account/src/index.ts:27 — `ACCOUNT_APP_PACKAGE_ID = 'com.objectstack.account'`, so the console URL is /_console/apps/com.objectstack.account/page/connect_agent.", "Precedent wording confirmed landed: packages/mcp/README.md:92-94 and content/docs/ai/connect-mcp.mdx:98-106." ] }, "firing_controls": [ "Control characters: `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the three edited files -> no output, exit 1. FIRING CONTROL: the identical pattern over a scratch file containing one U+0001 byte -> matched, exit 0. (An earlier attempt at a control that widened the class to include LF did NOT fire, because grep strips the line terminator; it was discarded and replaced with the one above.)", "Publish surface / symbol grep: `copy-paste-ready connect snippet` + `The in-product entry point` + `scripts, CI, headless agents` over packages/ apps/ examples/ -> zero hits. FIRING CONTROL: the identical grep over content/docs/ -> hits all three edited lines.", "files[] enumerator: 70 packages declare files[]; zero entries mention content/docs/mdx. FIRING CONTROL: the same enumerator does report @objectstack/lint shipping [\"dist\",\"README.md\",\"CHANGELOG.md\"] and @objectstack/spec shipping llms.txt / prompts / api-surface / spec-changes.json.", "eslint narrowing: `pnpm exec eslint --no-inline-config --format json` over the three .mdx paths -> 3 results, each `File ignored because no matching configuration was supplied.` = 0 files actually linted. FIRING CONTROL: the same invocation over eslint.config.mjs -> 1 lintable result.", "Pre-existing red attribution: `check:cross-package-test-inputs` at BASE 340b6dcf7 in a separate comparison worktree, zero of my edits present, WITH packages/spec/dist symlinked in -> exit 1 with the byte-identical finding. Same worktree, same commit, dist removed -> exit 0." ], "changeset": { "verdict": "skip-changeset (label applied)", "evidence": "Enumerated every files[] array in packages/ apps/ examples/ services/ (70 packages). The distinct entry set across the whole workspace is: CHANGELOG.md | README.md | api-surface | dist | json-schema | liveness | llms.txt | prompts | spec-changes.json | src/**/*.zod.ts. npm resolves files[] relative to each package root and content/docs/ sits above every package root, so no entry can reach it. apps/docs (the only thing that consumes content/docs) is `private: true` with no files[]. Symbol grep confirms: three distinctive strings from this diff return zero hits anywhere under packages/, apps/ or examples/. Not reasoned from 'docs are exempt' — the PM's named counter-example (packages/lint shipping CHANGELOG.md) was reproduced as the firing control." }, "tests": { "note": "Docs-only diff: no package source changed, so local-verification-scope leg (1) (dependency closure) and leg (2) (affected package test/typecheck) are both EMPTY — `turbo ls --affected` has nothing to schedule for three content/docs/*.mdx paths, and no package's public surface moved. Leg (3), the derived gate families, is the whole local obligation and it was run in full.", "gate_derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths passed; the script took its own change set from the merge base). Derived 39 runnable commands over the 3 paths.", "gate_reconciliation": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RANFILE => '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)', exit 0. Exit codes were recorded per command as `COMMAND :: exit CODE`, each captured with EXIT=$? before any pipe.", "gate_results": "38 of 39 exit 0. The one non-zero is `pnpm check:cross-package-test-inputs` :: exit 1 — PRE-EXISTING, proven below, not caused by this diff.", "prerequisite_reruns": "Four gates first returned PREREQUISITE NOT MET (their own wording; exit 3 for three of them, exit 1 for the fourth) because packages were unbuilt, NOT as findings: check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift. After `turbo run build --concurrency=2 --filter=@objectstack/lint --filter=@objectstack/formula --filter=@objectstack/client-react` (34 tasks successful) all four re-ran at exit 0. packages/spec was built first, separately, for the dist-reading gates.", "verify_lock": "Both builds went through `bash scripts/pm/os-verify-lock.sh -c ...` with OS_VERIFY_LOCK_SLOT=issue-18143. VERDICT command-exit 0 · held the lock 166s, waited 0s (spec build). VERDICT command-exit 0 · held the lock 480s, waited 0s (lint/formula/client-react build). No queue wait either time.", "eslint": "Repo-wide `pnpm lint` is CI's run, not mine. The narrowing is DECLARED and MEASURED, three legs, taken at final commit ccf23c895: (1) POPULATION read from eslint.config.mjs itself — the lintable globs are `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` plus narrower TS-only blocks at :1015/:1054/:1103/:1172/:1212/:1238; `.mdx` appears in none of them. (2) FILE COUNT from `--format json`: 3 results returned, every one of them `File ignored because no matching configuration was supplied.` -> 0 files linted, 0 errors. (3) INVARIANCE: eslint.config.mjs:326-330 states and the config confirms that this repo 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file' — with no type-aware program, an .mdx edit cannot move the verdict on any untouched file. All three legs present, so this is a measurement, not a skipped run.", "no_ablation": "No ablation or reverse verification applicable — prose-only diff, no gate or guard added, nothing to mutate." }, "pre_existing_red": { "gate": "pnpm check:cross-package-test-inputs", "verdict_here": "exit 1", "attribution": "NOT this diff. Reproduced at BASE 340b6dcf74df4f2e931e26f8fb795ce9b5dbf0cb in a separate comparison worktree (/home/user/objectstack-issue-18143-cmp) containing none of my edits: exit 1 with the byte-identical finding — '@objectstack/cli descends a directory tree from packages/spec/dist/ ... rooted in packages/cli/test/init-created-files-summary.e2e.test.ts ... packages/spec/dist/ (no declared glob reaches inside it)'. The finding names zero paths from my 3-file diff.", "further_measurement": "Its verdict is a function of LOCAL BUILD STATE, not of the tree. Same commit, same worktree, packages/spec/dist removed -> exit 0, 'OK: 29 package(s) read outside themselves, all declared ... 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII.' The `Lint & Repo Gates` job in .github/workflows/lint.yml runs `pnpm check:cross-package-test-inputs` (step 'Cross-package test inputs') with no preceding build of packages/spec, so CI only ever takes the green branch." }, "mcp_calls": "0 — no MCP GitHub tool was called at any point in this run.", "api_writes": "3 REST proxy writes, all with the environment GITHUB_TOKEN via curl: (1) POST /repos/objectstack-ai/objectstack/pulls -> 201, PR #18573 draft; (2) POST /repos/objectstack-ai/objectstack/issues/18573/labels -> 200, skip-changeset; (3) POST /repos/objectstack-ai/objectstack/issues/18143/comments -> this report. One earlier POST /pulls returned 415 (missing Content-Type) and wrote nothing; it is counted here for honesty, not as a write. Plus 2 git pushes (empty-branch routing probe, then the commit). No PATCH of any body.", "label_readback": "POST /issues/18573/labels was the additive endpoint. Labels BEFORE: []. Target: {skip-changeset}. union(read, target) = {skip-changeset}. Read-back AFTER: ['size/s', 'skip-changeset'] — the union is present, nothing was stripped. `size/s` is another actor's write (the size labeler) and was left alone.", "pr_body_readback": "GET /pulls/18573 read the stored body back in full. It differs from what was sent by exactly 1 byte (the trailing newline). First line is `Part of #18143`; `Clause-②: no` is present as its own line starting at column 0; the attribution footer appears exactly once, in session-URL form. No angle-bracket fragment exists anywhere in the body (scanned before sending), so there was nothing for the sanitizer to eat.", "open_questions": [], "out_of_scope_findings": [ "to file (3 classes, dedupe words): CLASS (a) reproducible defect — `check:cross-package-test-inputs` renders OPPOSITE verdicts on a byte-identical tree depending on whether packages/spec/dist/ exists on disk. At 340b6dcf7 without it: exit 0. Same commit, same worktree, with it: exit 1, naming packages/cli/test/init-created-files-summary.e2e.test.ts descending into packages/spec/dist/, 'no declared glob reaches inside it'. The Lint & Repo Gates job runs this gate with no preceding spec build, so CI can only ever take the green branch: the #7802 blind spot this gate exists to catch is unreportable in CI, while every developer who follows AGENTS.md's 'build spec before you believe a dist-reading gate' gets a red they did not cause. Dedupe words: cross-package-test-inputs, packages/spec/dist, init-created-files-summary, walked root radius, build-state-dependent verdict.", "noted, not filed: content/docs/ai/connect-mcp.mdx:100-106 spells each door with a direct /_console/... link, while the pages fixed here spell the same doors only as breadcrumbs. Pure consistency observation, no defect, no contract text violated. Successor: none — no open PR or reader path depends on the two spellings matching." ] }Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
落地记录 —— PR #18573 已合并;本卡 ⛔ 不关(
Part of),第四处仍被围栏挡着domain:devx执行席(座位贴 #6023,sessionsession_017ef78bLdybu3AffehKkhfk,round 15)。两读:⛔ 不看
merged布尔,⛔ 不看 head-sha 祖先性merged+removed_from_merge_queueorigin/main内容29a36f0bf87857be3a411d90dc81f833f4d881e4,parent 数 1git diff --stat M^ M⛔ 一条本席自己的更正:我的第一版探针形状是错的
我先写的探针是「三个文件里⚠️ 那是错的,而且它会把一次正确的落地读成半截 —— 因为本次修法是两扇门都点名,Setup 那扇对管理员仍然存在且必须留着。
Setup → Connect an Agent必须变 0」。⇒ 重写成真正的后置条件:
⭐ 这是本班同一条教训的又一次现形:先问这个仪器量的是什么。 一个"字符串消失"的探针,量的是"字符串消失",⛔ 不是"漂移消失" —— 而本卡的正确终态恰恰是那个字符串还在。
Release: 三处已落,第四处未落且有明确原因
content/docs/api/index.mdx(直接铸钥指令 ⇒ 两扇门都点名)·content/docs/ai/agents.mdx(描述性,且九行之上的 Callout 已把路由交给/docs/ai/connect-mcp⇒ 只去Setup →前缀)·content/docs/getting-started/build-with-claude-code.mdx(⭐ 只去前缀救不了它 —— 原句主语是Admins find …,删前缀后仍在告诉非管理员这是管理员去的地方 ⇒ 重写主语 + 两扇门)。content/docs/deployment/environment-variables.mdx:259。原因:维护者的 PR feat(spec,types,triggers)!:groupruns package-authored scheduled work without a declaration, owning each run's writes per record #18420 在飞并正在改该文件,本席在派发当刻读了 25 个 open PR 的files才发现 ⇒ 本轮围起,避免撞车。pm:queue、清 assignee。feat(spec,types,triggers)!:groupruns package-authored scheduled work without a declaration, owning each run's writes per record #18420 落或关之后另起一轮做第四处,届时本卡即可关。⭐ 这条围栏与本卡的来历同形:#17648 的 dev 当初正是因为落点在它申报的文件面之外而没有顺手改、另立了本卡,分诊把那件事记为正例。本轮轮到本席用同一条纪律 —— 文件面申报的作用就是让"没做完"变成一件写得出来的事,⛔ 不是拖延。
承接者交回的两条,处置写明
check:cross-package-test-inputs那条红 ⇒ [regression] check:cross-package-test-inputs 的裁决取决于被 gitignore 的空目录 packages/spec/dist 存不存在 —— 构建过的工作树一律红,CI 绿只因那一步跑在构建之前(#18340 引入) #18348 的第八次复现,⛔ 不另立卡。它这次的说法最完整:同一提交、同一工作树,packages/spec/dist在则 exit 1、不在则 exit 0 ⇒ 该门禁在字节相同的树上给出相反裁决;而 CI 里它前面没有构建步骤 ⇒ 只能走到绿的那一支,它存在的目的按构造不可报告。connect-mcp.mdx:100-106用直达链接、本轮三页用面包屑 ⇒ 纯一致性观察,⛔ 无缺陷、⛔ 无继承人。正确地没立卡。Generated by Claude Code
docs(mcp): name the Account door for Connect an Agent, not Setup alone (
docs: name both Connect-an-Agent doors in three published pages (obje…
os-try-charles commentedon Sep 18, 2026
Claim: PM loop round 44
Session:
session_017ef78bLdybu3AffehKkhfkBranch:
claude/issue-18143-connect-agent-env-var-rowWorktree:
objectstack-issue-18143-envDomain:
domain:devxFile surface:
content/docs/deployment/environment-variables.mdx(stop on breach; explain in the report)Container & model:
S 级机械卡,mode:subagent,model: opus(当次dispatch-gates.mjs --tier content/docs/deployment/environment-variables.mdx输出逐字:「no path-derived mandate: the surface hits none of the 3 declared glob(s)… floor sonnet · default opus · ceiling fable」)Clause-②: no
Thread-read: 5707808263
Serial constraints cleared: 25 个 open PR 的
files逐个读过(共读到 375 个变更文件 ⇒ 读法有反应),触碰本落点文件的只有 PR #18420(hotlong,draft,自 2026-09-17T16:16Z 未动)。⭐ 但它在 hunk 级不碰撞:#18420 对该文件只改 1 行,位置在:87一带(OS_AUTOMATION_SCHEDULED_WORK_ENABLED行),本卡余项在:260(OS_MCP_STDIO_API_KEY行)—— 相隔 173 行,远超 git 的三行上下文 ⇒ 无文本冲突。其余落点无任何在飞 PR 触碰。⛔ 一条针对本席自己第 15 轮判断的更正
第 15 轮本席把这个落点围了起来,理由写的是「#18420 碰这个文件」。⚠️ 那是一次文件级读数,被拿去裁一处行级编辑。 今天在 hunk 级重读,两处相隔 173 行,当时就不会冲突。
⇒ 代价是实打实的:这张卡因此在
pm:queue里多躺了 29 小时,而且看起来像「还有没人认领的活」,其实只剩一行。⭐ 这和本班反复栽的是同一个形状 —— 读数答的是另一个问题:问的是「这一行会不会撞」,量的是「这个文件有没有人碰」。「同一个文件」⛔ 不等于「同一处」。本卡此刻的真实余量:一行
在
origin/main(46559f61c,取数 2026-09-18T07:17Z)上把content/docs/**/*.mdx全部折行压平后数Setup → Connect an Agent,共 4 处(对照:Connect an Agent不限前缀 10 处 ⇒ 读法有反应):api/index.mdx:69**Account → Developer** … **Setup → Connect an Agent**getting-started/build-with-claude-code.mdx:436ai/agents.mdxSetup → Connect an Agent0 次ai/connect-mcp.mdxdeployment/environment-variables.mdx:260⇒ 落地后本卡关闭,PR 用
Fixes #18143(⛔ 不再是Part of)。读数时刻 2026-09-18T07:17Z
Generated by Claude Code
os-try-charles commentedon Sep 18, 2026
🚨 本条已改写:原文开头是一条行首的
Release:指令,而那条指令把本席自己当前有效的认领也一起撤销了。发生了什么(机器读出来的,⛔ 不是本席事后的说法)
原文是一条补记,补的是第 15 轮那次
Part of落地欠下的交接记录。但协议里的Release:是一条现在时的动作指令:它「无需 id,撤销其作者自己更早的全部认领」。它⛔ 没有「这条说的是上一轮」这种概念。check-clause2-carriers --pair 18959当场读出:⇒ 后果不是记账难看:
governingClaim返回 null,于是 H20 / H27 —— 那两条专门抓「派发被弃置」的行 —— 对这张卡整个失效,而此时 PR #18959 正开着。⭐ 一条为了补齐记录而发的评论,亲手制造了它想修补的那一类空洞。因此:第 15 轮的交接事实照录,但⛔ 不再用行首指令承载
session_017ef78bLdybu3AffehKkhfkPart of落地四个落点中的三个,卡按规矩⛔不关environment-variables.mdx:260)因串行围栏留待下一任认领pm:dispatched与 assignee 没有同笔清,交接行也从未写过 ⇒ 本卡在 2026-09-17T03:01Z 到 2026-09-18T07:17Z 之间约 28 小时处在「交付了一半、却没人说是谁放的手」的状态。H8 点名的就是它。pm:dispatched与 assignee 属于本轮的新认领(认领评论5726578170,派发的是那条余项),⛔ 不是第 15 轮的残留,⛔ 也不该被上面这段历史记录撤销。⭐ 教训一句:补记要用记叙的形式,⛔ 不能用协议里那条现在时的指令 —— 指令不读日期,只读作者。
改写时刻 2026-09-18T07:47Z
Generated by Claude Code
os-try-charles commentedon Sep 18, 2026
os-dev-report
{ "issue": 18143, "status": "done", "branch": "claude/issue-18143-connect-agent-env-var-row", "pr": "https://github.com/objectstack-ai/objectstack/pull/18959", "premise_still_valid": true, "summary": "Landed the remainder: the OS_MCP_STDIO_API_KEY row in content/docs/deployment/environment-variables.mdx now names both Connect-an-Agent doors instead of only Setup — '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, one file; the wording is copied from the two sibling pages PR #18573 landed rather than a fourth spelling, and compressed to fit a table cell (pipes 5, OS_ rows 133, still a single line). Every premise held when measured: origin/main is exactly 46559f61c; the file-level baseline reproduced the PM's numbers (corpus Setup→Connect-an-Agent 4, control 'Connect an Agent' 10, target file Account-door 0 / Setup-door 1); PR #18420's only hunk in this file is @@ -87,7 +87,7 @@ (the OS_AUTOMATION_SCHEDULED_WORK_ENABLED row), 173 lines from the edited row, so the hunk-level clearance holds and nothing of #18420 was touched. The card's assignee was already set (os-try-charles) and the newest Claim: names this branch and session — I wrote neither. Corpus close-out: the Setup door is still named in exactly 4 files by design, and all 4 now also name the Account door (carriers naming Setup but not Account: 0), so the defect class this card opened is closed.", "tests": "GATES — node scripts/pm/dispatch-gates.mjs --commands, derived in the worktree from the real change set (1 path vs merge base 46559f61c; committed 1, working tree 0, untracked 0): 39 families. All 39 run, all exit 0. Reconciled with exit codes recorded per family: `dispatch-gates --repo objectstack-ai/objectstack --ran` prints '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)'. PREREQUISITE-NOT-MET, re-run rather than reported as failures: check:doc-formula-expressions (exit 3), check:doc-security-posture (exit 3), check:docs-transcript-drift (exit 3) and check:skill-examples (exit 1, 'packages/client-react/dist holds no .d.ts declarations') — all four said 'Nothing was measured'. After `pnpm --filter @objectstack/spec build` (VERDICT command-exit 0, 169s) and `turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/client-react --filter=@objectstack/client` (VERDICT command-exit 0, 404s, '34 successful, 34 total'), all four re-ran at exit 0. Both builds went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-18143-env; waited 0s each. PROBE — written BEFORE the edit, and deliberately NOT 'Setup goes to 0' (that probe would read a correct landing as half-done, since the Setup door must stay named for admins). All counts on whitespace-FLATTENED files so wrapped prose cannot give a false zero; every zero paired with a control from the same population. A this-file 'Account → Developer' 0 -> 1 (POST >=1, met). B this-file 'Setup → Connect an Agent' 1 -> 1 (POST >=1, met: Setup stays). C control this-file 'Connect an Agent' unprefixed 1 -> 2 (nonzero both sides). D table integrity: OS_ rows 133 -> 133, pipes in the row 5 -> 5, lines for that key 1 -> 1. E corpus control over content/docs/**/*.mdx (404 files) 'Connect an Agent' 10 -> 11. Corpus carriers naming the Setup door but NOT the Account door: 0. ESLINT — a proven narrowing, not a skipped run: (1) population read from eslint.config.mjs itself, every files: glob enumerates ts,tsx,mts,cts,js,jsx,mjs,cjs and the string 'mdx' occurs 0 times in that config; (2) file count read from --format json: the changed .mdx returns 0 results while the positive control scripts/check-nul-bytes.mjs returns 1 result; (3) invariance — the config enables no type-aware linting for any file (its own header: '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. The repo-wide `pnpm lint` stays CI's run. CONTROL CHARS — grep -naP over the edited file: exit 1, 0 hits; positive control (a planted BEL byte) exit 0 with the hit printed, so the reader fires. pnpm check:nul-bytes exit 0. CHANGESET — skip-changeset, measured: 83 tracked manifests, 70 declare files[] (control: the reader resolves them, e.g. @objectstack/spec -> dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json); files[] entries reaching content/docs/**: 0. Symbol grep over the 2138 files those entries actually resolve to: 'Mint one from' 0 hits, 'Account → Developer' 0 hits, positive control 'objectstack' 1971 files. @objectstack/docs (apps/docs), the only consumer of content/docs/, is private: true. ABLATION — none run, and none is meaningful here: a one-line prose edit has no guard to delete and no dist to rebuild, so claiming an ablation would be theatre. The equivalent evidence is the before/after probe above, taken on the same flattened reader. NOT MEASURED (outside the derived total, as dispatch-gates says of itself): 52 artifact-roster families, 11 wide-population families, 14 pending-changeset families, 2 path-scheduled CI jobs (Test Core shards, Build Docs) and the always-runs tail. CI convergence is the PM's to read; gate status on the PR at report time is in_progress.", "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl", "api_writes": "5 — POST /repos/objectstack-ai/objectstack/pulls (draft PR #18959); POST /repos/objectstack-ai/objectstack/issues/18959/labels (skip-changeset, additive endpoint); POST /repos/objectstack-ai/objectstack/issues/18143/comments (this report); plus 2 git pushes (the empty-branch write-route probe, then the commit). Label read-back diff: union(read set, target) minus read-back = empty, nothing stripped; size/xs appeared from another actor and was left alone. Read-back proves the write landed, not that any gate reads the label.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: 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). They name genuinely admin-only surfaces addressed to admins, so none is the Connect-an-Agent defect — that one exists precisely because the page is ALSO delivered to non-admins through the `account` app. No defect; successor: none.", "noted, not filed: the card's four deliberately excluded carriers (docs/adr/0101-mcp-stdio-principal-admission.md:104, docs/qa/platform-checklist/areas/ai.json:206, two .changeset/*.md files) are dated records and were left untouched, as fenced. Successor: none — they are history, not drift.", "noted, not filed: `content/docs/ai/connect-mcp.mdx` routes with a direct console link while the four pages of this card's family use breadcrumbs. A pure consistency observation, already recorded by the previous round as having no defect and no successor; repeating it here so it is not lost, still not filed." ] }Generated by Claude Code
os-try-charles commentedon Sep 18, 2026
落地两读(卡 #18143 · PR #18959)—— 本卡四个落点收齐,随
Fixes自动 CLOSE。读① 队列侧 —— 时间线⚠️ 对照本轮读到 3,而 #18475 那次读到 0 —— 同一条读数在不同时刻强度不同,那次本席就把这条腿判为不成立。)
added_to_merge_queue2026-09-18T07:57Z →merged2026-09-18T08:11Z →removed_from_merge_queue→head_ref_deleted。这一腿的对照:同一次git ls-remote --heads origin 'gh-readonly-queue/*'读到其他队列分支 3 条 ⇒ 列表是活的,所以「本 PR 的分支不在」是读数,⛔ 不是空读。(读② 内容侧 —— 重取
origin/main(e19ae6708,取数 2026-09-18T08:12Z),探content/docs/deployment/environment-variables.mdx:Account → DeveloperMint one from **Setup残留OS_TENANCY_POSTURE(取自被探文件自身)对照是机械选出来的:先数 diff 命中为 0,再数落地后文件内命中非 0。⛔ 不从报告的叙述里挑名字,⛔ 也不挑「改动附近的词」——
git diff会打印上下文行,上下文行同样算命中(OS_MCP_STDIO_ENABLED就因此 in-diff=2 被否掉)。⛔ 两读都不取
merged布尔,也不取 head-sha 祖先关系。缺陷类收口,本席独立复核过
在 PR head 的独立工作树上,对
content/docs/**/*.mdx404 个文件折行压平后数:⇒ Setup 那扇门按设计仍被点名 4 次(它对管理员一直有效、也必须留着),⛔ 不是「消失了」才算修好。
⭐ 这一点值得单独记:本席在派发令里明写过「⛔ 别用『Setup 归零』当后置条件,那个探针会把一次正确的落地读成半截」。 第 15 轮本席第一版探针正是那个错形状,当场改掉;这一轮把它写进了派发令,施工席据此在动手前就写对了探针。
四个落点的最终状态
api/index.mdx·getting-started/build-with-claude-code.mdx·ai/agents.mdxdeployment/environment-variables.mdxai/connect-mcp.mdx席位状态随此清理:撤下
pm:dispatched,解除指派。读数时刻 2026-09-18T08:13Z
Generated by Claude Code
fix(pm): read the ownership markers through the undecorated line, and…
docs(deployment): name both Connect-an-Agent doors in the OS_MCP_STDI…