Repository navigation
docs(pm): name the landing flow's wait state when the ccr undraft route answers 429 - #19717
Conversation
…s 429
The landing flow's state list had no legal state for a 429 on
POST .../pulls/{n}/ccr/ready_for_review. A seat that met it held a fact
(the body's `resets at` instant), a prohibition (never retry before the
reset, never busy-poll) and no declared outcome, so it could only report
a dated wait as a blocked landing or invent a cadence.
The new line sits beside the arm act it belongs to: the 429 is returned
BY the ready flip, zero bytes written and `draft` unmoved, so the PR
never reaches the ready + all-green precondition the three-step enqueue
check is gated on.
Paid in-file at 69/69 by retiring the queue-only restatement: its rule
is already stated in SKILL.md ("the queue is the only sanctioned landing
path, never merge outside the queue"), and inside this file its only
work was bounding the two main-red exceptions, both of which already
carry their own bounds.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc
Contract reviewServed-tier: ① Derived judgmentsRendered in-seat by the skills seat 1 session at the served tier the maintainer named on this date (the fable tier word at
② Semver levelNone — no release. ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #18743
What lands
One rule line in
.claude/skills/pm-dispatch/references/landing-operations.md§B — the landingflow's own state list — naming what an arming run IS when the ccr undraft route
(
POST .../pulls/{n}/ccr/ready_for_review) answers 429. Before this, a seat that met that 429held a fact (the body's
resets atinstant), a prohibition (never retry before the reset, neverbusy-poll, never blind-retry) and no declared outcome, so its only exits were to report a
dated wait as a blocked landing or to invent a cadence — the thing the rules forbid.
Added at line 22, 120 bytes (the ratchet's per-line cap is 120, and a line of exactly 120 bytes passes — 34 lines of the
corpus already sit at exactly 120):
It carries the three parts the card's contract asks for — the named wait on the instant, the
instant recorded on the card, one retry at it — plus both prohibitions (⛔ not a blocked landing,
⛔ no self-chosen cadence). The facts stay where they are:
platform-readings.mdis not edited.Where it goes, and why there rather than the alternatives
Measured, not assumed. Three homes were on the table.
written,
draftunmoved. So the line belongs in the block that performs the flip (theflip-定点 →
绿即转 ready + 挂 auto-merge→ the no-busy-poll discipline). It sits immediatelyafter the CI-webhook line so that the pair
绿即转 ready…↔CI success webhook 不可靠…staysintact, and so the new state reads as the permitted action under that line's ⛔ 不坐等 /
⛔ 不忙轮询: the wait is a 定点 the platform names, not one the seat picks.
ready + 全绿 ≠ 已入队. A 429 leaves the PR not ready at all, so that precondition is falseand the three-step ladder never starts. Filing the state there would put it behind a door the
429 can never open.
rest-channel.md— rejected. That file is a per-operation channel table ("which routedoes this act take"), and it already carries the route. What is missing is not a route but a
landing state, and the landing flow's state list is §B here.
How the line is paid: the retired duplicate
landing-operations.mdis at ceiling 69 with headroom 0, so the line is paid in-file by retiringone. Retired:
Two independent covers, both checkable:
SKILL.md.SKILL.mdalready states路径面干净的才转 ready → 入队;队列是唯一被认可的落地路径,⛔ 永不队列外合并。— unconditional, andstrictly stronger than "don't relax it for any other PR". This file's own ceiling convention,
quoted in the ratchet's
CEILINGScomment for the 80 → 69 lowering, is verbatim"no rule already stated in SKILL.md". So the line is a duplicate by the file's declared standard,
not by my reading of it.
main-red exceptions directly above it, and both already carry their own bounds in their own
text —
限 p0、机械、根因已核实的止血 PRand仅限 main-red 修复. Nothing normative is lost withit gone.
Net: 69 lines before, 69 after. The ceiling is not raised and no cross-file move is declared.
Verification
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths — the script takes its own change set from the merge base), then reconciled with
--ran. Exit codes captured before any pipe, into a file.The families the dispatch named, with the verdict each printed:
pnpm check:pm-skill-ratchetlanding-operations.md is 69 lines (ceiling 69; headroom 0)·widest table row is 0 bytes (pin 0; headroom 0)pnpm check:pm-skill-id-lint30 file(s) clean (pattern /#[0-9]{3,}/g)pnpm check:skill-frame-syncthe one declared copy of the decision frame is internally coherent· 77 md files scanned for undeclared copiespnpm check:pm-governed-prose2 instruction surface(s) name all 6 registered governed surfaces and claim no otherspnpm check:doc-authoring403 files clean — no bare metadata literalspnpm check:nul-bytesscanned 9210 text file(s) … no raw ASCII control bytesThe other eleven derived families also exited 0:
check:pm-governed-merges,check:cross-package-test-inputs,check:driver-memory-census,check:agent-test-spelling,check:gitlink-declared,check:refd-timer-probe,check:watch-hint-literal,@objectstack/lint run check:doc-formula-expressions,check-closing-keyword-parity.mjs(bothwith and without
--self-test),check-comment-mask-corpus.mjsandcheck-harness-current.mjs --self-test. Four of them first answered exit 3 in the freshworktree (prerequisite not met — no
node_modules; one also needed@objectstack/formula+@objectstack/lintbuilt). Exit 3 is not a finding and was not recordedas one:
pnpm installand a lockedturbo run build --filter=@objectstack/formula --filter=@objectstack/lintcleared it and all fourwere re-run to a real verdict. The build ran through
scripts/pm/os-verify-lock.sh, which printedVERDICT command-exit 0 · held the lock 177s · waited 0s.Beyond the gate: a direct control-character sweep of the edited file,
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', exited 1 (no match).No ablation or reverse-verification run is claimed here: the change is one line of governed prose
with no executable behaviour, so there is nothing whose removal a test could be shown to detect.
The ratchet is the instrument that would have caught a miscount, and it is green at 69/69.
Changeset
skip-changeset. Measured rather than asserted:.claudeexists as exactly one directory inthe tree, at the repo root. The only package at the repo root is
@objectstack/spec-monorepo,which is
private: trueand declares nofiles[]. Of the 83 trackedpackage.jsonfiles, 70declare a
files[]and zero of their entries names.claudeunder any spelling; theremaining 13 are all
private: true. So nothing in this diff reaches a published tarball.Acceptance notes
No out-of-scope cards are owed from this round. One boundary worth recording, deliberately not
filed:
SKILL.mdandreferences/filing-gate.mdeach already carry a 429 rule (429 即停写/收到 429 或次级限流 ⇒ 该席本 fire 停写). Those govern the write budget on the claude[bot]token, a different pool from the session credential's GraphQL hourly pool that the undraft
route draws on, and they prescribe stopping writes — which is precisely what would push a
seat toward reporting the landing as blocked. They are near neighbours of the gap this PR
closes, not statements of it, and they are correct as written. An observation, so no card.
Generated by Claude Code