From 307068512555b6777e3a4b9f3d3c4608817dcea9 Mon Sep 17 00:00:00 2001 From: Param Harrison Date: Wed, 23 Sep 2026 20:30:18 +0300 Subject: [PATCH 1/2] Grant stage commands via agentCommands and add a demo runbook The runner no longer hard-codes bun/make grants, so splitbill declares them. Co-Authored-By: Claude Sonnet 5 --- .factory/config.json | 58 ++++++++++++++++++++++++++++++++++++++------ DEMO.md | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 DEMO.md diff --git a/.factory/config.json b/.factory/config.json index c3e00cc..ebbe5e5 100644 --- a/.factory/config.json +++ b/.factory/config.json @@ -2,11 +2,39 @@ "repo": "learnwithparam/splitbill", "base": "main", "baselineTag": "baseline", + "agentCommands": { + "read": [], + "build": [ + "bun *", + "make *" + ], + "verify": [ + "bun *", + "make *", + ".factory/gates.sh" + ] + }, "gates": [ - { "name": "typecheck", "cmd": "make typecheck", "required": true }, - { "name": "test", "cmd": "make test", "required": true }, - { "name": "skills", "cmd": "make skills-validate", "required": true }, - { "name": "audit", "cmd": "make audit", "required": false } + { + "name": "typecheck", + "cmd": "make typecheck", + "required": true + }, + { + "name": "test", + "cmd": "make test", + "required": true + }, + { + "name": "skills", + "cmd": "make skills-validate", + "required": true + }, + { + "name": "audit", + "cmd": "make audit", + "required": false + } ], "protectedPaths": [ "src/auth/**", @@ -31,19 +59,33 @@ "riskCriteria": { "_comment": "Guidance for the factory-plan skill, read by the agent, not by the runner. The runner only consumes riskPolicy.autoApproveLowRisk above.", "low": { - "criteria": ["docs-only", "test-only", "single non-protected module, no schema or API-shape change"], + "criteria": [ + "docs-only", + "test-only", + "single non-protected module, no schema or API-shape change" + ], "approval": "auto-approve if the Auto-approve low-risk plans toggle is on, else /factory approve" }, "medium": { - "criteria": ["more than one module touched", "adds or changes an API route or DB column", "dependency minor/patch bump"], + "criteria": [ + "more than one module touched", + "adds or changes an API route or DB column", + "dependency minor/patch bump" + ], "approval": "/factory approve" }, "high": { - "criteria": ["dependency major version bump", "touches a protected path", "planner confidence is low"], + "criteria": [ + "dependency major version bump", + "touches a protected path", + "planner confidence is low" + ], "approval": "/factory approve" }, "protectedPathRequired": { - "criteria": ["plan requires editing a protected glob"], + "criteria": [ + "plan requires editing a protected glob" + ], "approval": "refused at triage; never planned or built by an agent" } } diff --git a/DEMO.md b/DEMO.md new file mode 100644 index 0000000..8834370 --- /dev/null +++ b/DEMO.md @@ -0,0 +1,44 @@ +# Factory demo runbook + +Shows every way a human steers the factory, using this repo. Run `factory reset` first (it force-pushes +`main` back to the `baseline` tag; use `--dry-run` before the first time). + +## Setup + +```bash +cd ../factory +bin/factory doctor --repo-dir ../splitbill --fix +make up REPO_DIR=../splitbill # runner + dashboard on http://localhost:4100 +``` + +The runner polls every 15 seconds. All human input is GitHub state: a label, an issue comment, a draft +PR comment or review, or a dashboard button (which posts the same comment). Only OWNER, MEMBER and +COLLABORATOR count. + +## Live sequence + +| Step | Issue | Human action, and where | What you see | +|---|---|---|---| +| 1 | #16, #17 | add label `factory:ready` on the issue | low risk plans auto-approve, build, and a draft PR opens | +| 2 | #15 | on the draft PR, comment `/factory revise ` | the same PR gets a new commit, no second PR | +| 3 | #18 | comment `/factory revise ` on the issue at `awaiting-approval`, then `/factory approve` | plan revision 2, then build | +| 4 | #20 | high risk plan: comment `/factory cancel` | issue closed, worktree removed | +| 5 | #19 | none: it needs a protected path | refused at triage, nothing built | +| 6 | #21 | the agent asks a question: answer in the dashboard, or as a plain issue comment | resumes at the stage that asked | +| 7 | none | `bin/factory scan --repo-dir ../splitbill` | files the nanoid advisory as an issue | + +## Paths you cannot force live + +Timeouts, verify rejects, red gates, boundary hits, denied tools, a lost claim and crash recovery are +replayed offline, one named test each: + +```bash +cd ../factory && bun test tests/scenarios.test.ts +``` + +A structural test in that file fails if any state label has no scenario, so a new state cannot ship +untested. + +## After the demo + +Merge or close the draft PRs yourself; the factory never merges. From e95fd8930dc5646140162d992c99738b47e0d56e Mon Sep 17 00:00:00 2001 From: Param Harrison Date: Wed, 23 Sep 2026 21:05:31 +0300 Subject: [PATCH 2/2] DEMO.md: name issues by title, cover rebaseline, ready-for-review and delivery Co-Authored-By: Claude Sonnet 5 --- DEMO.md | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/DEMO.md b/DEMO.md index 8834370..4558d94 100644 --- a/DEMO.md +++ b/DEMO.md @@ -1,30 +1,39 @@ # Factory demo runbook -Shows every way a human steers the factory, using this repo. Run `factory reset` first (it force-pushes -`main` back to the `baseline` tag; use `--dry-run` before the first time). +Shows every way a human steers the factory, using this repo's seeded issues. Issue numbers change on +every reset, so the runbook names issues by title. ## Setup +Setup changes (config, charter, skills, CI) and demo output are handled differently by `reset`, which +force-pushes `main` back to the `baseline` tag and drops anything merged after it: + +1. Merge any setup PR into `main`. +2. `bin/factory rebaseline --repo-dir ../splitbill` moves the tag onto the new `main`, keeping the setup. +3. `bin/factory reset --repo-dir ../splitbill --dry-run`, then without `--dry-run`. The dry-run lists every + `drop-commit`; that list should be empty. + ```bash cd ../factory bin/factory doctor --repo-dir ../splitbill --fix make up REPO_DIR=../splitbill # runner + dashboard on http://localhost:4100 ``` -The runner polls every 15 seconds. All human input is GitHub state: a label, an issue comment, a draft -PR comment or review, or a dashboard button (which posts the same comment). Only OWNER, MEMBER and -COLLABORATOR count. +The runner polls every 15 seconds. All human input is GitHub state: a label, an issue comment, a PR +comment or review, or a dashboard button (which posts the same comment). Only OWNER, MEMBER and +COLLABORATOR count. A PR is a draft while the factory works and is marked ready for review when it hands +over to you. ## Live sequence -| Step | Issue | Human action, and where | What you see | +| Step | Issue (by title) | Human action, and where | What you see | |---|---|---|---| -| 1 | #16, #17 | add label `factory:ready` on the issue | low risk plans auto-approve, build, and a draft PR opens | -| 2 | #15 | on the draft PR, comment `/factory revise ` | the same PR gets a new commit, no second PR | -| 3 | #18 | comment `/factory revise ` on the issue at `awaiting-approval`, then `/factory approve` | plan revision 2, then build | -| 4 | #20 | high risk plan: comment `/factory cancel` | issue closed, worktree removed | -| 5 | #19 | none: it needs a protected path | refused at triage, nothing built | -| 6 | #21 | the agent asks a question: answer in the dashboard, or as a plain issue comment | resumes at the stage that asked | +| 1 | "Splitting $10.00 three ways loses a cent", "CSV export shows raw cents" | add label `factory:ready` on the issue | low risk plans auto-approve, build, and a PR opens, marked ready for review | +| 2 | "README has no run steps" | on its PR, comment `/factory revise ` | the PR goes back to draft, gets a new commit, and is marked ready again; no second PR | +| 3 | "Expense search leaks other groups' expenses" | comment `/factory revise ` on the issue at `awaiting-approval`, then `/factory approve` | plan revision 2, then build | +| 4 | "Upgrade hono 3.12.12 to 4.x" | high risk plan: comment `/factory cancel` | issue closed, worktree removed | +| 5 | "Any group member can delete any other member's expense" | none: it needs a protected path | refused at triage, nothing built | +| 6 | "Make settling up easier" | the agent asks a question: answer in the dashboard, or as a plain issue comment | resumes at the stage that asked | | 7 | none | `bin/factory scan --repo-dir ../splitbill` | files the nanoid advisory as an issue | ## Paths you cannot force live @@ -39,6 +48,9 @@ cd ../factory && bun test tests/scenarios.test.ts A structural test in that file fails if any state label has no scenario, so a new state cannot ship untested. -## After the demo +## Deliver and reset -Merge or close the draft PRs yourself; the factory never merges. +`main` requires a code-owner approval and the runner posts as you, so you cannot approve a factory PR +yourself. Merge one with an admin bypass (`gh pr merge --squash --admin`), then run +`bin/factory reset --repo-dir ../splitbill`: the dry-run lists that merge as a `drop-commit`, and the real +reset puts `main` back on the baseline. The factory never merges.