Skip to content

[PM seat] domain:engine — 🟢 zhuangjianguo #6367

Description

@hotlong

⚠️ This post is the RECORD of state, not the state. Every round, re-read the labels. Never read the counts here as current.

📌 Job description is versioned at .claude/skills/pm-dispatch/references/lanes/engine.md. ⛔ Not hand-copied per term.

1. Current PM — 🟢 zhuangjianguo

session session_01ARYe3yQTQCUFm5qPYNgKaJ · GitHub login zhuangjianguo · seated 2026-09-04T05:52Z via /pm-dispatch engine on the predecessor's shift-end brief (comment 5534857428, an explicit 「本席不再写」 release) · round R17 (opened 2026-09-04T05:52Z, marker 5536331483).

Standing parameters, carried forward: in-flight ceiling 5 (maintainer 2026-09-03, 「任务很多,并发保持5」, superseding 「后续并发降到4」). Devs AND isolated review subagents both count. ⛔ A Clause-② dispatch must leave a slot free for its reviewer.

⛔⛔ THIS SEAT IS OFF CONTRACT_REVIEW_TIER — re-measured 2026-09-04T05:5xZ, ⛔ not inherited

Tier is claude-fable-5-1 (scripts/pm/dispatch-gates.mjs:8659, read on origin/main). get_session returns session_context.model claude-opus-5 and last_served_model claude-opus-5.

⇒ ⛔ No Clause-② PR may be reviewed in-seat; each goes to an isolated subagent explicitly passed model: fable, fed card + rulings + PR only, adopted verbatim or voided whole. ⛔ Re-read the fuse with get_session every review session — it is a per-session fact, not a lane fact.

⚠️ Two different states the needs:contract-review label cannot tell apart — write which one it is, every time: gate unmet because no review happened (quota exhaustion, off-tier seat) vs gate unmet because a review FAILed. The predecessor's whole shift was the first kind.

2. Ledger — current values, 2026-09-04T06:2xZ

origin/main = 50d6c92. ⛔ Every landing below verified by CONTENT on origin/main, never by the API's merged field.

Inherited from R16, verified landed this round

card PR verified by
#14038 #15008 commit e37456e on origin/main
#14096 (census) #15122 commit fcc42e6
#13866 #15051 a54855005; disclosure follow-up #15131 merged 03:56:10Z
#14423 (step 1 census) #15033 4 probe scripts present under scripts/audits/14423-*

The predecessor's entire "in the merge queue" and "owed" list is discharged. #15131 did land (its brief said it could not; the brief's own correction 5534934123 records the maintainer merging #15051, and #15131 followed).

In flight — 1 of 5

target card surface
os-dev (opus, mode:subagent) #14970 priority:p0 security packages/objectql/src/engine.tspublishDataEvent :5629 + its 3 call sites :10286 / :11615 / :13069, plus a pin test

State corrections made this round — each paired with a comment in the same stroke

⭐⭐ Two of this round's five corrections were cards whose Blocked-by: target had closed while the condition it stood for had NOT been met. The unlock predicate is "the target closed"; the conditions were "the validator reads the key" and "the ledger still exists". ⇒ On every unlock candidate, read what the conversion comment actually made the wait ABOUT, then verify THAT against the tree. A closed blocker is a prompt to check, never the answer.

Decision box — ⛔ re-verify from labels every round, a ruling flips a label with no notification here

#14423 (new this round) · #14666 · #14147 · #14273 · #14025 · #13933 (pm:retriage, routing deadlock — carrier is triage's) · #13889 · #13636 (pm:awaiting-maintainer; PR #14923 voided on the maintainer's 「14923 直接作废」 — ⛔ do not touch either; superseded under ADR-0131 §1.6 / C11).

⚠️ New lane inventory this seat did not file and has not graded

#15194 / #15195 / #15196 — cut 05:44Z as the ADR-0131 execution tree, target:v18, priority:p1, security, all pm:blocked behind #15193 ("the v18 development line is not open"). #15195 carries an explicit ⛔ "Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say."
#15161 — the engine half of #14168, filed by the domain:spec seat 04:10Z. pm:queue with no domain:* ⇒ half-annotated, invisible to this lane's candidate query; grading is triage's.

3. Hot-file serial queue — 2026-09-04T06:2xZ

⭐⭐ READ THIS BEFORE THE CLAIM, NOT AFTER.

4. Notes — platform facts and lane disciplines that are current

  • ⭐⭐ The rate limit splits REST vs GraphQL, not read vs write. REST (pull_request_read, issue_write, add_issue_comment, actions_*) keeps working while GraphQL (issue_read, list_issues, search_issues, and update_pull_request — it does a GraphQL lookup before its REST write) all fail together. ⇒ draft→ready is structurally blocked when that bucket is out: GitHub exposes it only as GraphQL markPullRequestReadyForReview; REST PATCH /pulls/{n} has no draft field. ⛔ Do not route around it by merging directly.
  • ⭐⭐ Merge-queue membership: the only reliable POSITIVE reading is actions_list + event: merge_group (branch gh-readonly-queue/main/pr-<n>-<parent>). There is no cheap negative reading. ⛔ The arm receipt's filled/empty distinction carries no established meaning — the predecessor recorded one as a ⭐⭐ platform fact and then withdrew it (5530403273); both forms have preceded successful landings. ⚠️ mergeable_state: "unknown" is lazy computation, and is also exactly the shape a real conflict arrives in.
  • ⛔ Absence is not evidence, and a conflict sends no notification. fix(metadata-protocol): listCommits emits the ISO-8601 string createdAt declares #15008 sat armed for 7 hours because mergeable_state: "dirty" — auto-merge does not fire on a conflicted PR and nothing announces it. Only a positive diagnosis sees it.
  • ⭐⭐ Conflict resolution depends on the artifact's KIND; getting it backwards corrupts other people's work. A generated line-anchor table must be re-derived with its own tool's --fix (on a branch that shifts lines, take-theirs and take-ours are both wrong); an append-only ledger keeps BOTH rows; hand-written source preserves each side's intent.
  • ⭐⭐ engine.ts and protocol.ts line anchors move constantly. Measured this round: the card's anchors on objectql: publishDataEvent does not stamp the organizationId the spec now declares — the producer half of the #13566 p0 cross-tenant webhook leak, and nothing is filed for it #14970 were off by one, [finding] SqlDriver.update() keeps an explicit Promise[any] while returning null on a miss — the same published-type mask #14434 removed from driver-memory, inherited by TursoDriver and SqliteWasmDriver #14438's by 88, sys_email.error description says "transport error" but the column now also carries pre-delivery rejections #14372's generated anchor by 9. ⛔ Re-derive every anchor by symbol on your own head. ⛔ Never reason from a number written in a card, a brief, or this post.
  • ⭐⭐ Route the agent to the SOURCE and your own framing stops being load-bearing. "Read the card and every comment first, quote any ruling verbatim, ⛔ do not accept the PR body's paraphrase" has twice caught a ruling the seat had mis-framed as an open question.
  • ⭐⭐ A zero-hit grep is not a result without a positive control. Same for a dedup search: 「查不了」 is never 「查过了干净」.
  • ⭐ Populating an already-declared optional key on a path that previously omitted it is NOT a new key ⇒ Clause-② no (precedent metadata-protocol: the three recovery doors run no ADR-0094 mutation projector — a rollback restores the row and leaves the derived read-model on the rolled-back-FROM state #14415 at protocol.ts:20271; applied again this round on objectql: publishDataEvent does not stamp the organizationId the spec now declares — the producer half of the #13566 p0 cross-tenant webhook leak, and nothing is filed for it #14970, where the spec's own TSDoc states the producer obligation as part of the already-landed contract). ⚠️ Mechanical floor otherwise: any new exported symbol or new key on a published payload is always yes. Unsure ⇒ yes.
  • ⭐ A one-shot agent has no mid-run question channel and no background wake. Stop conditions must ask for evidence and close inside the agent's own round, and this belongs in dev prompts as well as reviewer prompts. ⛔ Never tell an agent to background long work and await a notification — the predecessor stalled three times on exactly that.
  • ⭐ In-flight count is a READING, not a memory. ListAgents answers it in one call. The predecessor reported a round as dispatched that never was, and repeated it for several rounds, because the list was memory.
  • ⭐ A dispatch premise handed over as a Zone 2 item gets falsified by the dev; one asserted as Zone 1 ships. When unsure, it is Zone 2.
  • ⭐ A cross-seat request must be a CARD in the target lane's queue — a seat-post knock or a ruling comment is invisible to that lane's candidate query, sweep and ageing alarms.
  • ⭐ A red check has three classes. Timeout ⇒ load. Assertion on product behaviour ⇒ regression. Assertion on the experiment's own validity premise ⇒ same class as a timeout. ⛔ "Flake" is not a root cause.
  • needs:contract-review is ⛔ never pre-hung (maintainer 2026-08-28): an open carrier must always mean a real pending review. It goes on the card and the PR in one stroke when the diff exists. Two lane cards were corrected for this by the director seat while this round ran ([finding] SqlDriver.update() keeps an explicit Promise[any] while returning null on a miss — the same published-type mask #14434 removed from driver-memory, inherited by TursoDriver and SqliteWasmDriver #14438, No platform object carries a timezone, so every app that computes a date boundary has to invent one — and each will invent it differently #14238) — ⛔ do not re-hang either by reflex.
  • Semver: envelope on a published verb ⇒ minor · new public-entry export ⇒ minor · published type narrowing ⇒ minor + BREAKING + adr-0087: · envelope on an existing refusal / accept-set widening ⇒ patch · published /meta read-door row-set change ⇒ patch · repairing an implementation that silently violated its own already-published declared type ⇒ patch · comment-and-test-only ⇒ skip-changeset. ⛔ major forbidden by check-changeset-no-major.mjs.
  • Readings: list_issues labels is OR and never returns assignees — use search_issues with label: + no:assignee + state:open · issue_read get_labels refuses a PR number while issue_write update on it succeeds · issue_read get returns closed_by_pull_requests, the cheapest way to see whether a PR carries a closing keyword · the PR side runs the AFFECTED subset; the queue build runs the FULL suite, so a PR green on its head can still eject · a PR can wait 45+ min for a queue slot · Test Core (1/6) is the long shard (12–26 min) · get_check_runs pages at 30, so perPage: 50 · list_pull_requests at perPage: 50, get_files on a large PR, and get_job_logs at tail_lines: 450 all EXCEED the tool token cap · dispatch-gates.mjs with NO path arguments derives the change set from git off the merge base and that derivation is authoritative over any hand-listed set⚠️ it also warns when run against a stale local tree, and that warning is load-bearing · use a three-dot diff against main.
  • Governed surfaces (docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md): draft-only. ⛔ Never flip ready / enqueue / arm auto-merge on own judgment; ⛔ never approve from an agent seat. packages/spec/** is not governed — that is lane ownership, a different question.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:enginepm:seatPM seat registry issue - single-writer body, index = this label

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions