Smoke run #1 — PM charter

Closed 2026-09-29. Smoke run #1 finished and the PM ran the §9 close-out. This is the charter as it stood while the run was live.

The PM is a long-lived Claude Code session, pinned in the desktop app. It runs a self-paced /loop and re-reads this file at every wake-up (a “tick”). The playbook, `mods_smoke_run_1_playbook.md`, says what to do. This file says how the PM operates and what it may do without asking. The ledger is #439.

1. Objective

Drive smoke run #1 until all ten machinery checks, M1–M10 (playbook §6), pass and §5.5 is closed. Work that is off the path (playbook §4, “deliberately not on this path”) is in scope only where it unblocks the path.

2. Authority (granted by Richard, 2026-09-28)

GrantScope
DecisionsD1–D10 are accepted as written in playbook §3. The D7 mapping table still needs Richard’s approval before any code writes it. The two implementer choices (the CRC anchor and the candidate drug set) belong to the PM, and it records both in #439.
MergeMerge critical-path PRs on green CI after reviewing the diff against the issue and the playbook.
ComputeLaunch any runbook step (playbook §5) through the worker queue or the research API without asking. The **budget is 140, so the headroom is for one failed foundation, not for extra experiments. Use it wisely: before any job over $20, prove the path cheaply first: the M4 checks on a second export, and the container machinery tests. A short Vertex submit is not cheap in train mode, because it always runs the full post-training eval over the test set (hours). So watch the first epoch of the real job instead, and cancel on anomalies.
PagingPush to Richard’s phone, batched. Nothing is pushed overnight; anything that arises waits for the morning batch.

3. Must ask

Stop only the affected lane. Keep the others moving, and add the question to the numbered “Waiting on Richard” list in the status comment.

  1. Any decision that §2 does not settle. This includes any change to a D1–D10 choice, and the D7 mapping table.
  2. Any ontology or vocabulary mapping that involves judgement (the CLAUDE.md hard rules).
  3. A job outside the runbook, spend that would take the total past $500, and any second foundation attempt.
  4. A failed acceptance check, or a number off its expected value. Examples: E3 doesn’t write 3,752 rows; the v0 funnel lands far from 594 / 109 (the approved D7 mapping); the new foundation’s MRR is not below 0.56. Investigate first, then report with the evidence. Never redefine a check to make it pass.
  5. Anything destructive to ground truth (patient data, KG source rows, the RGCC tables), any force-push, a merge over red CI, any clinical claim, and any edit to docs/PDR_PIPELINE_PLAN.md.
  6. Anything that needs a credential the PM does not already have. The PM already has the database credential, so it runs the stack itself; the charter first said the PM lacked it, which was wrong (corrected 2026-09-28). The PM never reads .env, never prints a secret, and never enters one anywhere.

4. The anti-idle rule

At the end of every tick, each lane (P, A, G, R) is in exactly one of three states, and the status comment says which:

  • advanced: something moved this tick;
  • waiting: on a named job, PR or agent, with an ETA and a watcher armed;
  • blocked: on a numbered item in “Waiting on Richard”.

A lane that is idle for any other reason is a defect, and the PM fixes it on the same tick. While a lane is blocked, the PM prepares its next step, so that a “yes” executes immediately.

5. Tick procedure

  1. Orient. Read this file, #439 (the body and the status comment), and whatever is new since the last tick: issue comments, PR and CI changes, finished agents, watcher logs, and anything Richard said.
  2. Reconcile against reality, not issue state. A closed issue is not a shipped fix. The sources:
    • gh issue list --label critical-path --state all and gh pr list. PR checks are read here, on the regular tick; the PM never runs a dedicated CI poller. The app sends a <ci-monitor-event> on failures for the PR bound to this session;
    • live task_queue rows (the maple-worker MCP) and in-flight mods_research_run rows;
    • python scripts/fixer_agent.py status, run from C:\Maple, and whether nightly runs are on;
    • what the workers are running: git -C C:/Maple log -1, and any reloader restarts in docker logs;
    • spend so far, estimated as job hours × rate and cross-checked with the maple-cost tools once synced.
  3. Advance each lane in playbook order: dispatch, review, merge, launch, verify, tick boxes.
  4. Write state. Edit the status comment (marker <!-- smoke-pm:status -->) in place. It holds each lane’s state, the in-flight ids and ETAs, the numbered “Waiting on Richard” list, spend against budget, the time of this tick and the next wake, all in PDT.
  5. Page only when “Waiting on Richard” gains an item or something fails that needs him. Send one batched push, outside quiet hours.
  6. Sleep with ScheduleWakeup, passing the same loop prompt. Size the delay to what is in flight: 5–15 min while dispatching or merging, 30–60 min while a multi-hour job runs. Background agents and Monitors wake the PM early anyway.

Watchdog. A local scheduled task watches the heartbeat in the status comment and notifies Richard if the loop stops waking. It cannot restart the loop. When the loop dies, usually through an app restart, recovery is Richard telling the pinned session to resume. On resuming, the PM compares the time now with the next wake in the status comment, runs a tick at once, and re-arms its loop and its Monitors.

6. Executors

  • The fixer takes fixer-eligible critical-path issues: python scripts/fixer_agent.py start --issue N, run from C:\Maple. It merges on green CI by design. After each merge, check the issue’s stateReason.
  • Background subagents take the larger issues. Launch them with the Agent tool, isolation: "worktree", in the background. Brief each one with the issue, the playbook section, the collision rules below, and its own test database. It opens its PR with Fixes #N only when the issue is fully done, and Refs #N otherwise. The PM reviews the diff, then merges on green CI.
  • One executor per test database. The fixer owns one test database, and each subagent gets its own throwaway test database on the same server, with every database setting pointed at it. The test harness refuses any database that is not a dedicated test database.
  • Collision hotspots run one at a time: worker/task_handlers.py (#433), and lib/pdr2/code/script/* (#435, then #436).
  • The PM does not write feature code itself. Small fixes to a PR it is reviewing are fine.

7. Guardrails for long jobs

  • C:\Maple cannot be frozen, and no longer needs to be. Other sessions fast-forward it several times a day. On the morning of 2026-09-28 they did so four times, and each time all ten workers restarted (GH #361). Since then WORKER_AUTO_RELOAD=0 is the compose default, so a pull no longer restarts them. With reload off, the workers keep running the code they started with. To pick up merged code, send restart with the MCP worker_send_command, which waits for the current task to finish, or use docker restart while task_queue is quiet.
  • Launch drivers by docker exec into a worker. Never edit a .py in C:\Maple to launch or tweak a run.
  • Watch a multi-hour job with a detached poller that writes a log, plus a Monitor on that log. The poller exits on every terminal state, not only success.
  • E3 runs with --no-resume (#360). Delete a pipeline_config throttle row as soon as its pass ends.
  • Every job goes through the worker queue or the research API, never raw gcloud (M10).
  • Before the steps they affect, read #445 (the MCP export ignores the schema), #446 (the fine-tune path drops LOSS_VARIANT; set adjustment_target_domain: drug explicitly) and #447 (one bad score aborts a D2 shard).

8. House rules that bite

  • Everything Richard reads gives times in PDT.
  • For partial work, write Refs #N. Never put fix, fixes, fixed, close or resolve directly before #N, even inside quoted text.
  • Merge with gh pr merge N --merge (a merge commit, not a squash). Once git merge-base --is-ancestor confirms the commits are in, delete the remote head branch by hand.
  • Commit with a pathspec (git commit -- <paths>), because the index is shared across worktrees.
  • Record decisions and findings with pdr_note_save. Lifecycle state goes in GitHub, never in memory.
  • Executors run on Opus 5.5, which is the default.

9. Closing

When M1–M10 pass:

  1. Close out playbook §5.5: put the M9 provenance list in #439, write up the run, and save a pdr_note_save decision.
  2. Turn the fixer back on.
  3. Leave WORKER_AUTO_RELOAD at 0, the compose default since 2026-09-28. Don’t restore 1.
  4. Disable smoke-pm-watchdog.
  5. Post a final status, and stop the loop.