Repository navigation
fix(pm): the relay reads no runner 403 as the egress proxy's, and a refused advisory row names its cause - #29505
Conversation
…efused advisory row names its cause write-pace: on an Actions runner no egress proxy stands in the path, so `proxyAnswered` never reads an answer there as the proxy's; a GitHub 403 in the relay takes rule ③ (the platform back-off path) instead of giving the slot back. `isProxyRefusal` now needs a positive proxy mark: its message, or a documentation_url on the proxy's own docs hosts, never merely "not github.com". fleet-write/execute: a refused advisory row prints its cause — the platform's message and documentation_url from the refusal's own answer, capped and kept to one table-safe line, never its errors or body — before the remedy, so the reading a seat puts to the maintainer carries the reason. A message or URL that reproduces prose of the payload or of the advisory the preflight read is withheld, and the row says so. Claude-Session: https://claude.ai/code/session_01J8VVAoLff4MC52HYARNBKP Co-authored-by: Claude <noreply@anthropic.com>
|
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J Contract-review-claim: session_01J8VVAnMUWA9rufXzFaEh4J · head 478c92a · 2026-11-02T16:51Z The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent (the seat session is not at that tier). |
|
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J Contract reviewServed-tier: Reviewer: an isolated contract reviewer at CONTRACT_REVIEW_TIER, read-only on GitHub, fed the card body and comments, the PR body, the net diff against the merge-base, the head's check-runs, contract-review.md and review-checklist.md. The dev report was read as input, not as conclusions; every count below is this review's own measurement. This record carries no finding, no mechanism, no advisory id and no advisory title; the self-test fixtures use made-up ids and a generic marker sentence, and none is repeated here. No environment variable value is printed anywhere in this record. ① Derived judgmentsThe card's three defects and the PR's claims, one at a time:
② Semver levelNone. No published package, no ③ Boundary flags
④ Design judgmentPer hits file, against the card's scenario (a second
Must-fix: none. Should-fix:
Check-runs at record time (2026-11-02T17:10Z): 46 check-runs on 478c92a, all completed, 26 success, 20 skipped, 0 failure, 0 in progress. Success: Lint & Repo Gates, TypeScript Type Check, Test Core, Governed Surface Queue Guard, Test UI, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · tooling self-tests, Lint · PM dispatch-gates, Lint · CI release & engine gates, Type Check · workspace/source gates/debt ledger/consumer gates, PR-body guards, Check Changeset, Check PR Size, Dogfood Regression Gate, Plan Test Core shards, Auto Label, filter. Skipped by path filter: Build Core, Lint UI, Type Check UI, Build & E2E UI, Live E2E UI and the opt-in lanes. Combined status Implemented-by: VERDICT: PASS with should-fixes (S1 PR-body Fixes/Part-of and the follow-up card; S2 quote check against the raw message; S3 status-0 wording) Generated by Claude Code |
… and a transport failure never reads as the platform's reason The prose-quote check now judges the raw message as well as the flattened one, against the known prose as given and flattened the same way, so a quoted run that straddles a pipe, a backtick, a quote or a line break is withheld. On status 0 (the fetch threw) the row says the request did not reach the platform instead of "cause, as the platform gives it". Claude-Session: https://claude.ai/code/session_01J8VVAoLff4MC52HYARNBKP Co-authored-by: Claude <noreply@anthropic.com>
|
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J Contract reviewServed-tier: Reviewer: an isolated contract reviewer at CONTRACT_REVIEW_TIER, read-only on GitHub, fed cr17's PASS on 478c92a, the one-commit delta, the current PR body, the head's check-runs, contract-review.md and review-checklist.md. The PR body's verification section was read as input, not as conclusions; every count below is this review's own measurement. This record judges only what moved since 478c92a; cr17's judgments stand where the code is unchanged. This record carries no finding, no mechanism, no advisory id and no advisory title; the self-test fixtures use a generic marker sentence and made-up ids, and none is repeated here. No environment variable value is printed anywhere in this record. ① Derived judgmentsThe delta, one claim at a time:
② Semver levelNone, unchanged from cr17. No published package, no ③ Boundary flags
④ Design judgmentPer hits file, against the card's scenario (a refused advisory row read by a seat that must decide whether to stop):
Must-fix: none. Should-fix:
Check-runs at record time (2026-11-02T17:28Z): 44 check-runs on 3f3345a, 43 completed (24 success, 19 skipped, 0 failure), 1 in_progress (Test Core 1/8). Success: Lint & Repo Gates, TypeScript Type Check, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · tooling self-tests, Lint · scoped · slot lookup & corpus, Lint · scoped · query-options erasure, Lint · PM dispatch-gates, Lint · CI, release & engine gates, Type Check · workspace/source gates/debt ledger/consumer gates, Governed Surface Queue Guard, PR-body guards (claim · duplicate · Part-of · single-writer path), Plan Test Core shards, Test Core (2/8), Test UI, Dogfood Regression Gate, Check PR Size, Auto Label, filter. Skipped by path filter or label: Check Changeset, Build Core, Build Docs, Build UI Deps, Lint UI, Type Check UI, Test UI shards, Build & E2E UI, Live E2E UI, Dogfood Verify CLI, Dogfood shards, UI Published Artifacts, Temporal Conformance, Schedule gate and the two opt-in lanes. Combined status Implemented-by: VERDICT: PASS with should-fix (S1 test precision: one case per half of the quote check, the status-0 cap, and the "only the raw message" wording) Generated by Claude Code |
|
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J 维护者速读
席位核对 — ACCEPT · domain:skills#1 · head
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41491992528 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41495587695 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Conflicts in scripts/pm/fleet-write/execute.mjs, resolved as follows: - the ops import list takes both sides: advisory_read's names and #29505's ADVISORY_STATE_SHAPE; - the battery map keeps #29505's advisory rows count and advisory_read's row; - advisoryPlatformText is imported again. #29505 moved the other advisory rows onto advisoryRefusalCause and dropped the import, but advisory_read's refused arm still quotes only the messages ADVISORY_PLATFORM_MESSAGES names (review S2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAng9QxNxoEzyWkqbW6
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J
Requested by Irene · project thread
os-dev · domain:skills#1 dispatch · session_01J8VVAoLff4MC52HYARNBKP
Part of #29402. The card's third bullet (the seat records the measured live 403 reason and its seat-side rule in
references/rest-channel.md) stays open for the seat after a live reading.Clause-②: no
Metadata-protocol: none
维护者速读
write-pace在那里不再把 GitHub 的 403 当成代理拒绝;403 改走平台退避路径(规则 ③),不再退回名额。documentation_url。"不是 github.com" 不再算数。message和documentation_url(各限 200 字符、压成一行),再接原有的处置建议,所以交给维护者的读数里有原因。rest-channel.md,本 PR 不含。What changes
scripts/pm/write-pace.mjsinActionsRunner(env)(GITHUB_ACTIONS === 'true') andproxyAnswered(body, env): never true on an Actions runner,isProxyRefusal(body)elsewhere.stopSignalFrom(now takingenv, defaultprocess.env) andnoteResponse(itsdeps.env) act onproxyAnswered, so a GitHub 403 inside the relay runner is judged by rule ③ and never gets the proxy's slot give-back and "No stop marker written" line.isProxyRefusalstays pure (body only, solabel-write.mjsandfleet-token.mjsbehave the same in a seat container) but needs a positive mark: the proxy's own message, or adocumentation_urlon the proxy's docs hosts (PROXY_DOC_HOSTS: anthropic.com, claude.com, claude.ai). A URL that is merely not on github.com no longer counts. GitHub's own refusals can point at a short link or a changelog post on another host, which is the likely shape of the misreading the card measured.scripts/pm/fleet-write/execute.mjsadvisoryRefusalCause(answer, known): the refusal'smessageanddocumentation_url, from its own answer only (nevererrors, never the rest of the body). The message is flattened to one table-safe line and capped atADVISORY_REFUSAL_MESSAGE_CAP(200, cut with a note). The URL is printed only when https-shaped and withinADVISORY_REFUSAL_URL_CAP(200). No message gives "cause unread".knownisadvisoryProseOfof the request body and, for the PATCH rows, of the advisory the preflight read. Ids, states, logins and URL-shaped words are left out. A message or URL (percent-decoded too) that reproduces any 16-character run of that prose is withheld, and the row says so. The message is judged raw as well as flattened, against the known prose as given and flattened the same way, so a quoted run that straddles a pipe, a backtick, a quote or a line break is still caught.confirmAdvisoryandadvisoryPreflightprint that cause between the status andADVISORY_ACCESS_REMEDY, so "put this reading to the maintainer" now hands over a reading that names the platform's reason. This replaces the six-stringADVISORY_PLATFORM_MESSAGESfilter on these two paths. The header says the same.Why
Card #29402 measured three defects on the live relay. After the first
advisory_report, every later report answered 403.write-paceprinted that the egress proxy had refused it, which cannot be true on a runner, so no stop marker was written and the slot was given back. The row printed no message because the platform's was not on the six-string list. So the "put this reading to the maintainer" advice went out with no cause in it, and nobody could tell a reporter limit from a missing permission.Verification
At 3f3345a, in objectstack-ai/objectstack (the contract review's S2 and S3 are the second commit; 478c92a is the first):
pnpm check:pm-write-pace: 118 cases pass across 12 batteries (rule ③ battery 14 → 19 cases). It also passes underGITHUB_ACTIONS=true, the shape CI runs it in.pnpm check:pm-fleet-write-execute: 242 cases pass across 21 batteries (advisory battery 27 → 32 cases). The marker sweep now covers 46 runs, up from 41, and finds the marker in no log line, row, summary, annotation or pace-log line.git checkout HEAD --, withgit statusclean afterwards:quotesKnownreturning false turns 5 of 240 execute cases red, the marker sweep among them, andproxyAnsweredignoring the runner turns 3 of 118 write-pace cases red.git hash-objectof the file equals the head blob.node scripts/pm/dispatch-gates.mjs --commandsderives 36 commands for the two paths. At 478c92a all 36 exited 0, each exit captured before any pipe, and--ranreconciles 36 of 36. At 3f3345a, which changesexecute.mjsalone,check:pm-fleet-write-execute,check:pm-write-pace,check:nul-bytes,check:scripts-symbol-anchors,check:doc-authoring,check-self-test-wiredand eslint over the file were run again, all exit 0. Also clean:pnpm check:doc-authoring, eslint over both files, and the self-tests oflabel-write,fleet-token,post-stamped,issue-create,close-cards,issue-transfer,sweep-closed-cards,sweep-stale-finding,fleet-write/dispatchandfleet-write/validate.scripts/pmchanges, which publishes nothing, so the PR carriesskip-changeset.Acceptance notes
references/rest-channel.mdas the card's third bullet asks. It is left out of this PR because the reason has not been measured.retry-afterorx-ratelimit-remaining: 0. A bare 403 carrying none of them writes none, by rule ③'s own judgment ("a plain 403 does NOT"). The runner's pace log is fresh on every run anyway, so stopping repeat sends from seats rests on the row's cause and the remedy's ⛔ do-not-re-send.ops.mjs's header still says a refusal quotes the platform's message only when it is oneADVISORY_PLATFORM_MESSAGESnames.ADVISORY_ACCESS_REMEDYstill says what the App may do "is decided by the first live run".ADVISORY_PLATFORM_MESSAGESandadvisoryPlatformTextnow have no production caller;validate.mjs's self-test is the only one left.label-write.mjsline 420 still describes the proxy mark as "adocumentation_urlthat is not GitHub's".execute.mjsis also being changed on pm/fleet-write: an advisory_read relay op that returns an advisory only as ciphertext, encrypted to a one-time key the seat generates per read #29420's branch. Whichever lands second mergesmain(no rebase), and the seat re-reviews the delta.Human Minimum
packages/specholds no runtime logic. (Not touched.)main, one pull request.packages/specnot touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.pnpm lintandpnpm testwere not run; the scripts touched have no package tests, and eslint over the changed files was run.)🤖 Generated with Claude Code
https://claude.ai/code/session_01J8VVAoLff4MC52HYARNBKP
Generated by Claude Code