Skip to content

docs(adr): ADR-0066 D4 cites isSameOriginApiTarget by symbol anchor, and the requiredPermissions docblock drops its door clause - #27965

Merged
os-zhuang merged 1 commit into
mainfrom
claude/project-thread-vovpce
Oct 30, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/project-thread-vovpce

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

Part of #27694

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:ADR-0066 D4 对 isSameOriginApiTarget 的裸名引用改成符号锚 packages/runtime/src/action-execution.ts#isSameOriginApiTarget,由 check:adr-symbol-anchors 守住;同时删掉那句「符号上 main 后由 docs(adr): after the api-action door lands, rewrite ADR-0066 D4's isSameOriginApiTarget citation into a symbol anchor and drop the requiredPermissions docblock's "Landing" door clause #27694 改写」的待办。requiredPermissions 文档注释的「Landing」段删掉「门禁仍拒收 type: 'api'」这一条款,控制台条款保留。
  • 为什么改:fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649 已合并,平台动作门禁现在会派发同源 type: 'api' 动作。随 @objectstack/spec 的 .d.ts 发出去的注释还说门禁拒收,这对作者和 agent 是错话;ADR 用裸名引用,代码改名也没有门禁会发现。
  • 风险与回滚:两个文件 +5/−7,只动 ADR 正文和一段 JSDoc 注释,不改 .describe()、不改代码、不发布(skip-changeset);回滚即 revert 这一个提交。
  • 先看:packages/spec/src/ui/action.zod.ts 的 requiredPermissions 注释末段(Landing 段),再看 docs/adr/0066-unified-authorization-model.md D4 第二段的那处引用。
  • 两分钟验证:pnpm check:adr-symbol-anchors,预期 exit 0,计数为 611 个符号锚(585 个声明锚),比 main 上的 610 多一个,多出的就是这条锚,此后符号改名或挪走会转红。
  • 需要你做的:暂无。contract review owed(契约复审未完成,席位复审后再求批);本 PR 改 ADR 与 packages/spec/src,落地为 Tier H,由受管批准人批准。

What changes

Two files, +5 / −7, on base ca54eaca.

No .describe() changes, no code, no generated file.

Why

Deviations from the dispatch order

Acceptance notes

These go stale with #27649 but are outside this card's file surface or its ruling, so they are left as is:

Verification

All readings are on head 701d5499 (base ca54eaca).

dispatch-gates: 74 derived families, 74 exit 0

node scripts/pm/dispatch-gates.mjs --commands was run with no paths, on the committed diff against merge base ca54eaca. It derives 74 families, and all 74 were run with exit codes captured before any pipe. Prerequisites were pnpm install --frozen-lockfile --ignore-scripts and turbo run build --filter=@objectstack/spec --filter=@objectstack/formula --filter=@objectstack/lint. Two families first exited 3 (PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:lean-entry-closure, both needing built dist outside spec). After a whole-tree turbo run build (lock VERDICT command-exit 0), both exited 0: 113 published require entry points across 70 packages load, and the objectql/core admitted set holds exactly. check:dts-closure, check:sourcemap-no-sources-content and check:published-files were re-run over the whole built tree: exit 0, 115 / 108 / 74 packages swept. --ran: 74 derived famil(ies) accounted for — 74 run, 0 NOT-MEASURED. Re-derived after the run, the list was identical.

The ADR gates in the list: check:adr-symbol-anchors, check:adr-anchors, check:adr-index, check-adr-links.mjs (+ --self-test), check-adr-0087-registration.mjs, all exit 0. check:adr-symbol-anchors counts 611 symbol anchors (585 declaration) and 2161 file-level on this head, against 610 (584) and 2162 on ca54eaca. The bare-path citation of action-execution.ts became a declaration anchor, so the new anchor is in the gated population. Spec-docblock gates: check:spec-docblock-symbol-anchors, check:docs, check:api-surface, check:authorable-surface, all exit 0. check:nul-bytes exit 0.

@objectstack/spec typecheck and tests
  • pnpm --filter @objectstack/spec run typecheck: lock VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec run test: Test Files 756 passed (756), Tests 22481 passed | 1 todo (22482), lock VERDICT command-exit 0.
  • No ablation: the diff changes prose and a comment, not tested behaviour.

git merge-tree against origin/main bacb3e6a is clean, and no commit since the base touched either file. --tier answers MANDATORY claude-fable-5-1 for docs/adr/**. The claim records the proactive low-headroom downgrade, compensated by the contract-tier review. Changed lines: 12 (+5 / −7), under the 3000 threshold.

Contract review owed: governed docs/adr/** and packages/spec/src/**, at CONTRACT_REVIEW_TIER. That review also answers the Clause-② path leg on packages/spec/src/**. Landing is Tier H.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (a JSDoc comment only)
  • 2. Every name I added uses the casing for its kind. (no names added)
  • 3. No formatter ran; pnpm lint passes (prose only; the full run is CI's).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset. It changes a comment only, no .describe() and no code, so skip-changeset. Both declaration lines are above.
  • 6. packages/spec touched: nothing to regenerate. The change is a JSDoc comment. After the spec build and all 74 gate runs, the tree was clean (git status empty), and check:docs exited 0.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 is the sanctioned Chinese channel).
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…requiredPermissions docblock drops its door clause

Since the server half landed, the action door dispatches a same-origin
`type: 'api'` action, so the docblock's "the door still refuses
`type: 'api'`" clause is false and goes. Its console clause stays until
step 3 lands. ADR-0066 D4's bare `isSameOriginApiTarget` citation becomes
the symbol anchor held by check:adr-symbol-anchors.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4d1LtiXudcBaRgY2xRg
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 30, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:ui labels Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 58 of 210 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json bacb3e6a0ff6e8bfdeade49d6830e34fb5522589 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 510bb6c38b02f541462074cef35b143897a7192e — the merge of head 701d54993ffd1e89db86dfb21d385bc933e0c8ad into base bacb3e6a0ff6e8bfdeade49d6830e34fb5522589, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 510bb6c38b02f541462074cef35b143897a7192e && git checkout 510bb6c38b02f541462074cef35b143897a7192e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bacb3e6a0ff6e8bfdeade49d6830e34fb5522589 701d54993ffd1e89db86dfb21d385bc933e0c8ad && git checkout -B drift-repro bacb3e6a0ff6e8bfdeade49d6830e34fb5522589 && git merge --no-ff 701d54993ffd1e89db86dfb21d385bc933e0c8ad

node scripts/docs-audit/affected-docs.mjs --json bacb3e6a0ff6e8bfdeade49d6830e34fb5522589

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract-review-claim: session_016WV4d1QkPVVzNz3FJqb2iS · head 701d549 · 2026-10-30T05:33Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 701d54993ffd1e89db86dfb21d385bc933e0c8ad
Local-runs: probe — node scripts/check-adr-symbol-anchors.mjs (self-test, then the gate) on head 701d5499 and on base ca54eaca in two detached worktrees, removed afterwards, to confirm the new anchor is in the gated population; nothing else was built or run.
Scope: packages/spec/src/ui/action.zod.ts, docs/adr/0066-unified-authorization-model.md + packages/runtime/src/action-execution.ts (isSameOriginApiTarget, isHeadlessInvokableAction, headlessActionTypeError, SERVER_DISPATCHED_ACTION_TYPES, buildApiActionRequest, invokeBusinessAction), packages/runtime/src/domains/actions.ts (the REST door's forward), packages/runtime/src/domains/mcp.ts (the bridge's isHeadlessInvokableAction filter), ui/packages/app-shell/src/hooks/useConsoleActionRuntime.tsx and ui/packages/app-shell/src/views/RecordDetailView.tsx (the console's apiHandler), scripts/check-adr-symbol-anchors.mjs (the gate that holds the anchor), .changeset/27610-adr-0066-d4-api-actions-door.md (read only for the stale-landing-note question)

Inputs: git diff origin/main...FETCH_HEAD (2 files, +5 / −7, one commit on base ca54eaca, merge base clean against origin/main bacb3e6a), the PR body and its two comments (6515776463 docs-drift bot, 6515788043 the claim), card #27694 and its five comments (6506768233, 6513062223, 6513910736, 6514960778, 6515779258), card #27611 (open, with PR #27793 open against it), the dev report at /mnt/project-files/skills-lane-seat2/report-27694.json, and the head's check-runs.

① Derived judgments

  1. Accept set: unchanged — correct. The only hunk in packages/spec/src/ui/action.zod.ts is inside the JSDoc block above requiredPermissions. The z.array(z.string()).optional().describe(...) line is a context line in the diff; git diff ... | grep -c "^[-+].*describe(" is 0. No key, value, default or refinement moves, so no published accept set changes and no content/docs/references/ page regenerates. Clause-② no holds; this record answers the path leg on packages/spec/src/**.
  2. Door clause: fully removed and was false — correct. On head, packages/runtime/src/action-execution.ts#isHeadlessInvokableAction (line 1026) returns isSameOriginApiTarget(action?.target) for type === 'api', and headlessActionTypeError (line 1562) answers null when type === 'api' && isSameOriginApiTarget(action?.target). Both come from fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649 (481ade61c), which git merge-base --is-ancestor confirms is an ancestor of both origin/main and the head. The removed sentence ("the door still refuses type: 'api' (isHeadlessInvokableAction admits script, flow and the declarative update only)") was therefore false on main; no fragment of it survives in the new paragraph.
  3. Rewording around the cut: every remaining sentence is true. "ADR-0066 records the decision" — the dated D4 amendment is in the file. "The server half, the ruling's step 2 (Packaged action activation: switching off an api-type packaged action (Ban User) does not stop it, because the activation consult runs only at action dispatch #27506), is on main (fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649)" — fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649's title names Packaged action activation: switching off an api-type packaged action (Ban User) does not stop it, because the activation consult runs only at action dispatch #27506 and the commit is on main. "Until step 3 (Console: send a same-origin type: 'api' action click through POST /actions/:object/:action instead of fetching its target directly (ruling on #27506, step 3 of 3) #27611) lands the console fetches target directly" — Console: send a same-origin type: 'api' action click through POST /actions/:object/:action instead of fetching its target directly (ruling on #27506, step 3 of 3) #27611 is open; useConsoleActionRuntime.tsx apiHandler (lines 411–499) builds url = resolvedTarget.startsWith('http') ? resolvedTarget : baseUrl + resolvedTarget and calls authFetch(url, init); RecordDetailView.tsx apiHandler (lines 1422–1537) mirrors it. Neither posts to /api/v1/actions/:object/:action for an api action. PR fix(console): a declared same-origin type: 'api' click goes through the action door #27793 is open against Console: send a same-origin type: 'api' action click through POST /actions/:object/:action instead of fetching its target directly (ruling on #27506, step 3 of 3) #27611 but not merged, so the clause stays true on main. "Card docs(adr): after the api-action door lands, rewrite ADR-0066 D4's isSameOriginApiTarget citation into a symbol anchor and drop the requiredPermissions docblock's "Landing" door clause #27694 removes this paragraph when it does" — matches seat 1's note 6506768233 (second pass drops the console clause and closes the card). The deviation is justified: a bare cut would have left "Until it [the server half] lands the console fetches target directly", which is false. The retained date "as of 2026-10-29" is consistent with fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649's merge on that date.
  4. ADR anchor: resolves, and the sentence around it reads true. isSameOriginApiTarget is export function at packages/runtime/src/action-execution.ts:1083. Its body — non-string or length under 2 false, must start with /, second char must be neither / nor backslash — is exactly the ADR's "starts with exactly one / and goes on past it (/ alone, //host and /\host are not)". "The door holds the interpolated path to the same test before it forwards" — buildApiActionRequest re-tests isSameOriginApiTarget(path) after interpolation (line 1257) and answers 400 otherwise; the REST door calls buildApiActionRequest then forwardApiAction (domains/actions.ts:839-843) and the MCP bridge goes through invokeBusinessAction (domains/mcp.ts:871), which calls buildApiActionRequest at line 3348. "The route and the bridge" — both consume isHeadlessInvokableAction (mcp.ts:832, action-execution.ts:3216). The scheduling clause "once the symbol is on main, card docs(adr): after the api-action door lands, rewrite ADR-0066 D4's isSameOriginApiTarget citation into a symbol anchor and drop the requiredPermissions docblock's "Landing" door clause #27694 rewrites this citation" is gone; grep "card #27694" on the head ADR returns nothing. The kept parenthetical "(PR fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649; the door holds the interpolated path ...)" is unchanged in meaning.
  5. Gate population: the anchor is held. Local probe: head 611 symbol anchors (585 declaration, 26 literal), 2161 file-level; base 610 (584, 26), 2162 file-level; self-test and gate exit 0 on both. The +1 declaration / −1 file-level pair is exactly this citation (the bare action-execution.ts path became a declaration anchor). This matches the PR body's numbers.
  6. No generated artifact is owed. git grep "Landing, as of 2026-10-29" on the head tree hits only the source file; no api-surface/*.json, api-surface-signatures.json, declaration-map, docs/ snapshot or content/docs/references/ page carries the docblock paragraph. The dev report records a clean tree after a whole-tree build and check:docs exit 0, consistent with that reading.
  7. PR body declarations present and correct. Part of #27694 (not Fixes, per 6506768233); Clause-②: no; Metadata-protocol: none; label skip-changeset on the PR; Check Changeset skipped by the label. Author is objectstack-fleet[bot].

② Semver level

No release. skip-changeset is right: the diff changes a JSDoc paragraph and ADR prose; the .describe() text (the published description and the generated references) is byte-identical, and no runtime behaviour or type moves. The shipped .d.ts bytes of @objectstack/spec change in a comment only, which the review rules class as shipped bytes, not the published accept set. The prior #27664 changeset (.changeset/27610-adr-0066-d4-api-actions-door.md) already carries the Metadata-protocol: semantic record of the meaning change; this PR adds no meaning. Consistent.

③ Boundary flags

  • Dev flags: open_questions is empty. Three declared deviations: (1) rewording around the cut — accepted, see ① item 3; (2) no dated amendment note — accepted, see ④; (3) skip-changeset via pr_create and no assignees — procedural, not a contract matter.
  • Independence: the diff was produced by session_016WV4d1LtiXudcBaRgY2xRg on branch claude/project-thread-vovpce; this record is rendered by session_016WV4d1QkPVVzNz3FJqb2iS, which did not draft the diff. The claim 6515788043 names this head.
  • Cross-domain: the packages/spec docblock edit rides the domain:skills card under the exception declared in claim 6514960778 and admitted by triage 6513910736.
  • Tier: Tier H (docs/adr/**, packages/spec/src/**); the maintainer merges. Draft PR, mergeable_state: blocked.
  • CI (check-runs on head at 2026-10-30T05:36Z): 0 failed. Green: Lint · ESLint, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Auto Label, Dogfood Regression Gate, Plan Test Core shards. Still in progress: Lint · repo and tooling gates (this is the job that runs check:adr-symbol-anchors), Build Core, Build UI Deps, Live E2E UI, Test Core 1/8–8/8. Skipped by design: Check Changeset, Check PR Size, Build Docs, UI Published Artifacts, Temporal Conformance, Dogfood Verify CLI, the opt-in harnesses. The all-green condition for landing is not yet met at the time of this record; the local probe covers the one gate this diff can turn red.
  • The docs-drift bot comment 6515776463 lists nothing and says so is not a clean bill; the diff names no derived anchor, so nothing is expected there.

④ Design judgment

Implemented-by: claude/project-thread-vovpce
Reviewed-by: session_016WV4d1QkPVVzNz3FJqb2iS

VERDICT: PASS

Must-fix: none.

Should-fix:

  1. (carrier: docs(adr): after the api-action door lands, rewrite ADR-0066 D4's isSameOriginApiTarget citation into a symbol anchor and drop the requiredPermissions docblock's "Landing" door clause #27694 second pass, not this PR) ADR-0066 Status line: amend "The server half lands under Packaged action activation: switching off an api-type packaged action (Ban User) does not stop it, because the activation consult runs only at action dispatch #27506; see the note under D4." to record that it landed (fix(runtime)!: a same-origin type: 'api' action is dispatched through the action doors, so its packaged-action switch holds (#27506) #27649, 2026-10-29), in the same pass that drops the console clause once Console: send a same-origin type: 'api' action click through POST /actions/:object/:action instead of fetching its target directly (ruling on #27506, step 3 of 3) #27611 is on main.
  2. (carrier: landing, not a code change) Landing waits for the in-progress check-runs: Lint · repo and tooling gates, Build Core, Build UI Deps, Live E2E UI and the 8 Test Core shards were still running when this record was written; the maintainer's Tier H approval should follow their convergence.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

维护者速读

席位意见:ACCEPT。契约复核 PASS,没有 must-fix。should-fix 1:ADR-0066 的 Status 行仍是现在时("The server half lands under #27506"),转到 #27694 第二遍,与删控制台子句一起改,因此本 PR 写 Part of #27694,卡保持打开。should-fix 2(等 CI 收敛)已满足:现在全绿。

席位核对

@os-zhuang
os-zhuang marked this pull request as ready for review October 30, 2026 05:59
@os-zhuang
os-zhuang enabled auto-merge October 30, 2026 05:59
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 3986f9f Oct 30, 2026
64 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-vovpce branch October 30, 2026 06:35
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 protocol:ui 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