Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

broomva/p9

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

8 Commits

Repository files navigation

p9 — bstack P9: productive-wait primitive (the wait optimizer)

Never sleep on a blocking wait. P9 is a wait optimizer — turn any blocking external operation (PR CI, push-triggered deploys, builds, long indexing) into work on the next priority. PR CI is the canonical implementation today; the primitive is broader.

Why P9 exists

When an agent kicks off a long external operation and waits for it, the dumb pattern is sleep. P9 replaces it with productive-wait discipline:

  1. Notification via run_in_background — for PR CI, the observer is gh pr checks --watch. No polling.
  2. Productive wait — the agent drains a context-scoped queue (session → memory → graph → docs → Linear) while the operation runs.
  3. Self-heal — when CI fails for known categories (lint, format, codegen drift, flaky tests), P9 classifies and applies the heal command. Unknown failures escalate to a Linear ticket.
  4. Merge stays governed — P9 emits MERGE_READY; the existing .control/policy.yaml + control-gate-hook authorizes the actual merge. P9 owns mechanism, not policy.

Scope today vs. on roadmap

P9 currently tracks PR-scoped waits through the p9 watch <pr> CLI. That covers ~95% of agent waits in a typical session.

The remaining 5% — non-PR waits — are not yet wired into p9 watch. These include:

  • Push-triggered deploys — a push to main that fires a Vercel/Cloudflare deploy hook without opening a PR
  • Long-running test suites or builds — outside the CI surface
  • External index / sync operations — content pipelines, embeddings, search-index rebuilds

For these, the productive-wait discipline still applies: kick off next-priority work, then do one direct check on the operation's completion. Never sleep. Wiring these into p9 watch <kind> <ref> is on the roadmap.

Quick start

# 1. Install dependencies (stdlib-only at runtime; pytest for tests)
python3 -m venv .venv && source .venv/bin/activate
pip install -r tests/requirements-dev.txt
# 2. Wire policy blocks
# Add ci_watch: and ci_heal: to your .control/policy.yaml. See
# tests/fixtures/policy-good.yaml for a complete example.
# 3. Verify install
python3 scripts/p9.py doctor
# → p9 doctor: ok
# 4. Use it
gh pr create ... ; PR=42
python3 scripts/p9.py watch $PR --background
# In parallel: pull productive work while CI runs
python3 scripts/p9.py wait-queue pop
# When the bg-task notification fires, check terminal state:
python3 scripts/p9.py status --pr $PR --json

Subcommands

Command Purpose
p9 watch <pr> Spawn gh pr checks --watch in background, transition to WATCHING.
p9 status [--pr N] Show in-flight PRs and their state-machine position.
p9 wait-queue {push,pop,list,clear} Manage the productive-wait queue (5 sources, priority-ordered).
p9 heal <pr> --classify Read failure log, classify against the rubric (read-only — does not execute heals).
p9 events tail Stream P9 events (P1 conversation-bridge consumes these).
p9 merge-ready <pr> Mark a green PR as ready for metalayer-authorized merge.
p9 doctor Health-check: gh auth, state directory, policy blocks, rubric.

Architecture (one paragraph)

Pure Python, stdlib-only at runtime. State lives in ~/.config/broomva/p9/state.jsonl (append-only, JSONL with flock serialization, partial-write recovery on read). Failure classification is regex-only — no LLM in the hot path — driven by references/scoring-rubric.md (markdown is human-canonical; _builtin_rubric() in scripts/p9.py is code-canonical; a unit test asserts they stay in sync). The evaluator scores progress with a four-term weighted sum (signature change + failures decreased + budget remaining + classifier confidence) and forces escalation after two consecutive sub-floor cycles. Multi-PR concurrency is bounded by ci_watch.max_concurrent_prs (default 1). Everything fails closed on missing or malformed policy blocks.

Cardinal invariant

P9 never silently drops state. Every failure produces (a) a state.jsonl event, (b) a Linear ticket via the escalation channel, or (c) both. If neither write succeeds, P9 crashes loudly (exit 99) — degraded silent operation is forbidden.

Where it fits in the bstack

P3 (Linear ticket) → P4 (PR pipeline) → P9 (CI watcher + heal) → metalayer authorizes merge
 ↓ drains during wait
 {context queue, P5 worktree, P6 bookkeeping}

Composes with — does not duplicate — existing primitives. See AGENTS.md in the workspace repo for the full bstack specification.

Spec & design

The full design lives at broomva/workspace under docs/superpowers/specs/2026-05-04-p9-ci-watcher-design.md. Seven rounds of clarifying Q&A locked the architecture before a line of code was written.

Tests

python3 -m pytest tests/
# 46 passed

License

MIT — see LICENSE.

Related

About

bstack P9 — CI watcher + productive-wait primitive. Replaces sleep-based CI waits with an event-driven control loop, drains a context-scoped wait-queue while CI runs, classifies failures, and self-heals known categories. Merge authorization stays with the control metalayer.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /