Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Run `python3 <skill>/scripts/<name>` (`bash` for `.sh`). `name: purpose — argu
- vacuous_test_gate.py: a changed test file must really run and assert. — [REPORT] (--changed PATH... | --base…
- vendor_drift.py: list vendored skill files in TARGET that differ from the… — TARGET [--src DIR]
- wired_check.py: warn when a NEW script has no caller. — BASE HEAD [--root DIR]
- No documented CLI: _clean_union.sh, _dirty_guard.sh, _lock.sh, admission_check.py, board_common.py, bypass_guard.py, ceo_altitude_guard.py, comms_guard.py, context_nudge.py, cost_statusline.py, decision_gate.py, destructive_guard.py, destructive_guard_core.py, finding_guard.py, flake_ledger.py, gh_rest.py, handback_cap.py, handoff_inject.py, heavy_gate.py, host_accept.py, host_installer.py, host_safety.py, landing_watchdog.py, lane_cap.py, lane_resume_nudge.py, lkg.py, outcome_claim_guard.py, peer_ack.py, perun_auto_update.py, pipe_mask_guard.py, pipeline_profile.py, plan_gate.py, pregate_parity.py, red_main.py, repeat_poll_guard.py, reply_cap.py, restore_ledger.py, scope_creep_check.py, session_brief.py, stall_guard.py, subagent_brief_lint.py, surface_check.py, terse_reply_check.py
- No documented CLI: _clean_union.sh, _dirty_guard.sh, _lock.sh, admission_check.py, board_common.py, bypass_guard.py, ceo_altitude_guard.py, comms_guard.py, context_nudge.py, cost_statusline.py, decision_gate.py, destructive_guard.py, destructive_guard_core.py, finding_guard.py, flake_ledger.py, freeze_hook.py, gh_rest.py, handback_cap.py, handoff_inject.py, heavy_gate.py, host_accept.py, host_installer.py, host_safety.py, landing_watchdog.py, lane_cap.py, lane_resume_nudge.py, lkg.py, outcome_claim_guard.py, peer_ack.py, perun_auto_update.py, pipe_mask_guard.py, pipeline_profile.py, plan_gate.py, pregate_parity.py, red_main.py, repeat_poll_guard.py, reply_cap.py, restore_ledger.py, scope_creep_check.py, session_brief.py, stall_guard.py, subagent_brief_lint.py, surface_check.py, terse_reply_check.py

### business-ops
- bizops_check.py: Deterministic arithmetic checks business-ops already states… — [input.json] (stdin when no path)
Expand Down
3 changes: 2 additions & 1 deletion .claude/skills/agentic-delivery/INDEX-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Generated by `scripts/skill_index.py` (do not hand-edit). The script half of `IN
| `scripts/_dirty_guard.sh` | Sourced by scripts that run git checkout\|switch\|reset on a caller-given tree. | — |
| `scripts/_lock.sh` | Sourced by train scripts. | — |
| `scripts/admission_check.py` | flag a per-PR admission config that omits a test class the batch (merge train) runs, and a stale sp… | — |
| `scripts/baseline_guard.py` | store a test baseline only when it is not poisoned by load. | baseline_guard.py --fails FILE --rerun 'CMD {id}' --out BASELINE.json [--normal N] [--max-factor F] [--max-load L] |
| `scripts/baseline_guard.py` | store a test baseline only when it is not poisoned by load. | baseline_guard.py --fails FILE --rerun 'CMD {id}' --out BASELINE.json [--normal N] [--max-factor F] [--max-load L] [--f… |
| `scripts/bg_admit.py` | admission for background and shadow jobs, plus a lint for mktemp without a cleanup trap. | bg_admit.py admit SCRIPT... |
| `scripts/board_common.py` | shared post grammar and forge I/O for the board_* scripts. | — |
| `scripts/board_post.py` | compose one typed, capped, privacy-linted coordination post. | board_post.py --repo O/N --issue N --agent ID --type CLAIM --refs '#12' \ --body-file note.md [--ttl 90] [--post] board… |
Expand Down Expand Up @@ -38,6 +38,7 @@ Generated by `scripts/skill_index.py` (do not hand-edit). The script half of `IN
| `scripts/focus_gate.py` | no work outside the owner's open priority until that priority is done or blocked. | focus_gate.py status [common options] [--evidence FILE] focus_gate.py check [common options] [--item REF] [--paths P ..… |
| `scripts/focus_kit.py` | keep agents on task across long sessions and compactions: handoff, memory lint, docs map. | focus_kit.py handoff set\|add SECTION TEXT \| memory-lint [DIR] \| docs-index [--check] \| measure |
| `scripts/freeze_gate.py` | while a freeze is on, allow only deletions and red-trunk fixes. | freeze_gate.py BASE HEAD |
| `scripts/freeze_hook.py` | PreToolUse(Bash) hook: while a freeze is on, deny git push and gh pr merge. | — |
| `scripts/gh_rest.py` | curl REST fallback for gh api when gh's Go TLS fails inside a macOS sandbox. | — |
| `scripts/handback.py` | lane handback, gates to merge | handback.py --sha SHA --base REF --branch BRANCH --gate-cmd CMD [--gate-cmd CMD ...] |
| `scripts/handback_cap.py` | SubagentStop hook: cap a subagent handback, log how far it is from fields-only, and audit each lane… | — |
Expand Down
9 changes: 5 additions & 4 deletions .claude/skills/agentic-delivery/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ Generated by `scripts/skill_index.py` (do not hand-edit; rerun it after changing
| `references/dev-env-ownership.md` | booting a dev server in a lane, separating the serving tree from the committing tree, re-running a… | 8423 |
| `references/fanout-host-sizing.md` | sizing a fan-out or capping in-flight write lanes, cutting per-lane cycle-time or handback verbosit… | 12456 |
| `references/fast-agentic-delivery.md` | sizing a heavy-lane fan-out on a shared machine (the full environment-probe procedure and the fan-o… | 1703 |
| `references/flow-guards.md` | wiring or tuning the issue-dedupe hook, the per-fix fitness check, or the delivery-flow alarms. | 526 |
| `references/focus-kit.md` | a session runs long or compacts, a new session must resume the work, or memory files and docs grow… | 1308 |
| `references/full-map.md` | a delivery needs more than the SKILL.md fast path: the full gate table with every hard condition, t… | 6122 |
| `references/full-map.md` | a delivery needs more than the SKILL.md fast path: the full gate table with every hard condition, t… | 6149 |
| `references/gate-epistemology.md` | adding a gate (4) | 2950 |
| `references/host-enforcement.md` | claiming that state, permissions, or spend are *enforced* rather than merely followed, briefing a w… | 11228 |
| `references/incident-response.md` | drafting an incident runbook, defining severity levels or status/comms templates, setting up a brea… | 3264 |
Expand All @@ -22,19 +23,19 @@ Generated by `scripts/skill_index.py` (do not hand-edit; rerun it after changing
| `references/pipeline-optimizer.md` | a delivery pipeline is slow (a commit or push hook over about a minute, CI over about ten minutes,… | 4870 |
| `references/production-grade-product-playbook.md` | you are shaping a user-facing product surface in G3 Design, so you build to the domain-P quality ba… | 1658 |
| `references/project-state.md` | beginning multi-step delivery, changing objectives, transferring ownership, checkpointing, or recov… | 1885 |
| `references/red-gate-triage.md` | a gate, union, or CI check is red and you must decide whether it is real: attributing a red union (… | 7169 |
| `references/red-gate-triage.md` | a gate, union, or CI check is red and you must decide whether it is real: attributing a red union (… | 7133 |
| `references/retrospective.md` | running G10, or when a target's own incident/postmortem practice is in scope for a review. | 1273 |
| `references/roles.md` | standing up (or running) the full delivery team on a repo: who does what, when a hat fires, which g… | 6830 |
| `references/support-ops.md` | the product has users who file tickets, bug reports, or feature requests, and you need a support sy… | 1113 |
| `references/template-adr.md` | G3 Design must record a decision — an interface, NFR budget, or data/security choice — as an ADR (c… | 660 |
| `references/template-onepager.md` | G0 Intake turns a vague idea into a brief the owner can approve in one reply, or when /idea drafts… | 416 |
| `references/template-postmortem.md` | G10 or an incident meets retrospective.md's mandatory-trigger criteria and you must write the blame… | 879 |
| `references/unattended-operating-mode.md` | an agent or a Conductor is granted a block of unattended time to work a backlog — an overnight or m… | 6980 |
| `references/unattended-operating-mode.md` | an agent or a Conductor is granted a block of unattended time to work a backlog — an overnight or m… | 6709 |
| `references/unattended-trackers.md` | deciding whether an open issue's fix is absent, placing an auto-close keyword or a gate-parsed PR-b… | 11803 |
| `references/verification-handback.md` | delegating visual/parity work by measured number, running or finalizing verification, writing a lan… | 15206 |
| `references/work-tracking.md` | a repo uses a work tracker (Linear first-class | 1051 |
| `references/worktree-isolation.md` | isolating a lane's worktree: stale refs, git stash, out-of-tree scratch, an assignment path, a work… | 4120 |

## Scripts

106 scripts. Read `INDEX-scripts.md` when you need a script (a trigger and CLI per script). `../INDEX.md`, `### agentic-delivery`, has only each one-line purpose and arguments.
107 scripts. Read `INDEX-scripts.md` when you need a script (a trigger and CLI per script). `../INDEX.md`, `### agentic-delivery`, has only each one-line purpose and arguments.
11 changes: 11 additions & 0 deletions .claude/skills/agentic-delivery/references/flow-guards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Flow guards: finding_guard, fitness_tick, flow_alarm (canonical)

Read this when: wiring or tuning the issue-dedupe hook, the per-fix fitness check, or the delivery-flow alarms. Other files link here; they do not restate it.

**Search before you file (`finding_guard.py`).** A hit on a closed issue or PR is a regression to reopen, not a new filing. The operating-layer PreToolUse hook runs `file_finding.py` on every `gh issue create --title` and denies a match. Override with `# finding-force: <reason>` in the command; a failed search fails open.

**Every fix ships one executable fitness check (`fitness_tick.py`).** Put it in `.perun/fitness/` (exit 1 plus a one-line reason on failure). The loop runs `python3 .claude/skills/agentic-delivery/scripts/fitness_tick.py` each tick and prints `ALARM name: reason`. Close the fix only when `fitness_tick.py closable NAME` passes: 2 consecutive real passing ticks and a real caller, meaning a hook/settings/package JSON, CI workflow, shell script or Makefile line that runs the tick, or a loop entry (`loop.md`, a `routines/` file) whose line starts with the command. A prose or comment mention is not a caller.

**One symptom alarm, not a monitor per invariant (`flow_alarm.py`).** Each tick run `flow_alarm.py symptom`: ready PRs but nothing merged in 2h, or `--red-since` trunk red over 1h. **Stop starting:** the same script is a PreToolUse hook that denies `gh pr create` while 5 or more PRs sit ready-but-unmerged (`PERUN_STOP_STARTING_READY`; override `# priority: <reason>`), because waiting work is queue. **Measure before optimizing agents:** `flow_alarm.py split export.json` prints median waiting-to-start, coding and ready-to-merged hours and the largest stage.

**Freeze (`freeze_gate.py`, `freeze_hook.py`).** A freeze is a file (`.perun-freeze`, `<git-common-dir>/PERUN_FREEZE` or `$PERUN_FREEZE`). Pre-push runs `freeze_gate.py BASE HEAD` (deletions and `Red-Trunk-Fix:` commits only); the fail-closed PreToolUse hook `freeze_hook.py` also denies `git push` and `gh pr merge` while the file exists. Lift the freeze by removing the file.
1 change: 1 addition & 0 deletions .claude/skills/agentic-delivery/references/full-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ chat may be terse.
| Task | Open |
|---|---|
| Land PRs as a train | `scripts/merge_train.py`, `scripts/train_land.sh`; depth `references/merge-queue-worktrees.md` |
| Issue-dedupe hook, per-fix fitness check, flow alarms, stop-starting, freeze | `references/flow-guards.md` |
| Fix a red gate or union | `references/gate-epistemology.md`, `references/red-gate-triage.md`; repeat flake: `scripts/flake_ledger.py` |
| Start a lane | `templates/lane-preamble.md`: paste into every lane brief |
| Isolate a lane's worktree | `references/worktree-isolation.md` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ audit gate in every train; run the audit on the bare base first and report `BASE

**Before a flaky-test fix, list the open PRs that touch that test file** (`gh pr list --state open --json number,headRefName,files`) and add the fix to the holder's PR rather than opening a second one; the pre-push hook runs `flake_holder.py`, which warns naming the holder (warn, never refuse).

**Never store a poisoned baseline.** Store a baseline only through `python3 .claude/skills/agentic-delivery/scripts/baseline_guard.py --fails F --rerun 'CMD {id}' --out B.json --normal N`: it re-runs each failure solo (a solo pass is load, dropped), records the 1-minute load at start, and refuses a run with far more failures than normal. **A quarantine entry needs a ticket and an expiry** (`flake_ledger.py quarantine --ticket T`); a full list (`--max`, default 10) exits 1 and `--file-issue` files a P0, it is not a note for a human. **A freeze is a file, not a message**: while `.perun-freeze` (or `<git-common-dir>/PERUN_FREEZE`) exists, `freeze_gate.py BASE HEAD` (run by pre-push) lets through only pure deletions and commits with a `Red-Trunk-Fix:` line.
**Never store a poisoned baseline.** Store a baseline only through `python3 .claude/skills/agentic-delivery/scripts/baseline_guard.py --fails F --rerun 'CMD {id}' --out B.json --normal N`: it re-runs each failure solo (a solo pass is load, dropped), records the 1-minute load at start, and refuses a run with far more failures than normal. **A quarantine entry needs a ticket and an expiry** (`flake_ledger.py quarantine --ticket T`); a full list (`--max`, default 10) exits 1 and `--file-issue` files a P0, it is not a note for a human. **A freeze is a file, not a message**: see `references/flow-guards.md` (Freeze).

**Load flakes must not sink a train.** A train that is all-or-nothing under load can merge nothing for hours: failures that
looked new all passed when re-run alone. With `RERUN_CMD` (and optionally `BASELINE_FAILS`), `train_land.sh` re-runs each
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ loop, not a single task**. Frame it as the default stance:
**While the owner is away, `defer` alone — never a posted message**: a decision
request posted mid-run scrolls past and is unfindable later; the ledger, not the
chat, is the record. Before deferring, check `task_ledger.py questions` for a
near-duplicate already answered, so a settled question is never re-asked. Before filing an issue, search closed issues and PRs by meaning; a hit is a regression to reopen, not a new filing: the operating-layer `finding_guard.py` PreToolUse hook runs `file_finding.py` on every `gh issue create --title` and denies a match (override: `# finding-force: <reason>` in the command; a failed search fails open). **Every fix ships one executable fitness check** in `.perun/fitness/` (exit 1 plus a one-line reason on failure) that the loop runs each tick with `python3 .claude/skills/agentic-delivery/scripts/fitness_tick.py` (prints `ALARM name: reason`); close the fix only when `fitness_tick.py closable NAME` passes (2 consecutive real passing ticks and a caller that runs the tick). **One symptom alarm, not a monitor per invariant**: each tick run `python3 .claude/skills/agentic-delivery/scripts/flow_alarm.py symptom` (ready PRs but nothing merged in 2h, or `--red-since` trunk red over 1h). **Stop starting**: the same script is a PreToolUse hook that denies `gh pr create` while 5 or more PRs sit ready-but-unmerged (`PERUN_STOP_STARTING_READY`; override `# priority: <reason>`), because waiting work is queue. **Measure before optimizing agents**: `flow_alarm.py split export.json` prints median waiting-to-start, coding and ready-to-merged hours and the largest stage. On the
near-duplicate already answered, so a settled question is never re-asked. Before filing an issue, search closed issues and PRs by meaning; a hit is a regression to reopen, not a new filing. Dedupe hook, per-fix fitness check, symptom alarm and stop-starting: `references/flow-guards.md`. On the
owner's **next** message, whatever it says, **answer it first**, then append the
full open batch from `questions` — never lead with the backlog of asks. Once
`answer` records a reply, the ledger drops that item from the pending batch (it
Expand Down
19 changes: 13 additions & 6 deletions .claude/skills/agentic-delivery/scripts/baseline_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
baseline. Before a baseline is stored: re-run its failures one at a time, record the host load at start, and refuse a run
whose failure count is far above normal.

baseline_guard.py --fails FILE --rerun 'CMD {id}' --out BASELINE.json [--normal N] [--max-factor F] [--max-load L]
baseline_guard.py --fails FILE --rerun 'CMD {id}' --out BASELINE.json [--normal N] [--max-factor F] [--max-load L] [--force]

--fails FILE failing test ids of the candidate baseline run, one per line (blank lines ignored).
--rerun CMD solo re-run command (shlex-split, no shell); `{id}` is replaced by the test id; exit 0 = passes solo.
--normal N the usual failure count of a healthy run. With it, more than F x max(N, 1) failures (F default 3) REFUSES.
--max-load L refuse when the 1-minute load average at start is above L (default: no limit; the value is always recorded).
--normal N the usual failure count of a healthy run (default 5). More than F x max(N, 1) failures (F default 3) REFUSES.
--max-load L refuse when the 1-minute load average at start is above L (default: 2 x cores, `PERUN_GATE_CORES` overrides
the core count; the value is always recorded).
--force skip both refusals (a deliberate, visible override); the solo re-run still happens.
Writes BASELINE.json {"fails": [ids that still fail solo], "flaky": [ids that passed solo], "load1": X, "stored_at": epoch} and
exits 0. REFUSE (exit 1, one `REFUSE baseline: <reason>` line, nothing written): too many failures, or load above --max-load.
Exit 2 on usage error or unreadable FILE. A solo re-run that cannot start counts as still failing. Side effects: the one
Expand Down Expand Up @@ -38,20 +40,25 @@ def main(argv=None):
ap.add_argument("--fails", required=True)
ap.add_argument("--rerun", required=True)
ap.add_argument("--out", required=True)
ap.add_argument("--normal", type=int)
ap.add_argument("--normal", type=int, default=5)
ap.add_argument("--max-factor", type=float, default=3.0)
ap.add_argument("--max-load", type=float)
ap.add_argument("--force", action="store_true")
a = ap.parse_args(argv)
if a.max_load is None:
a.max_load = 2.0 * int(os.environ.get("PERUN_GATE_CORES") or os.cpu_count() or 1)
try:
ids = sorted({ln.strip() for ln in open(a.fails, errors="replace") if ln.strip()})
except OSError as e:
print(f"baseline_guard: {e}", file=sys.stderr)
return 2
load1 = os.getloadavg()[0] if hasattr(os, "getloadavg") else 0.0
if a.max_load is not None and load1 > a.max_load:
if a.force:
pass
elif load1 > a.max_load:
print(f"REFUSE baseline: load1 {load1:.1f} above --max-load {a.max_load}; re-take it on a quiet host")
return 1
if a.normal is not None and len(ids) > a.max_factor * max(a.normal, 1):
if not a.force and len(ids) > a.max_factor * max(a.normal, 1):
print(f"REFUSE baseline: {len(ids)} failures, far above normal ({a.normal} x {a.max_factor:g}); the run is suspect")
return 1
flaky = [t for t in ids if solo_passes(a.rerun, t)]
Expand Down
Loading
Loading