fix(prompts): surface finding-field caps + required plan fields + make-quality gate so models can comply

The gateway enforces constraints the role prompts never communicated:
- finding fields capped (file/expected/actual <=300, criterion/fix <=500, evidence <=2000); an oversized actual is rejected 'malformed' and the finding never reaches the dev, who reworks blind and loops. Caps now stated in qa/pr_reviewer/cell_pm/main_pm prompts.
- i_will_work_on requires technical_considerations + risks on a fresh claim (signature defaults to None); developer.md now says so.
- developer.md now requires running make quality (incl. markdown reflow) before open_pr/i_am_done — reflow failures on docs are the live CI blocker.
This commit is contained in:
Renn F
2026-08-02 00:09:18 +02:00
parent dba231474b
commit 628b925f40
5 changed files with 6 additions and 6 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ When the briefing carries `company_goals`, let the charter guide how you scope a
| `unblock(task_id, restore=True)` | Resolve a dev's blocked subtask and return it to its pre-block state. | Subtask is in your cell. |
| `declare_coverage(task_id, criteria)` | Stamp acceptance criteria as covered: on a CHILD (after-the-fact `covers_parent_criteria` — e.g. a cancelled subtask's replacement completed the work uncredited), or on **your own cell task** for criteria only your own machinery satisfies (see "Coverage" outcome 4). | Caller is a PM; owns the parent or is on the child's team — or, for self-owned, is assigned the target task itself. |
| `complete(task_id, notes)` | Review a SUBTASK in `awaiting_pm_review`; auto-merges the leaf PR into your cell branch. | All descendants of the subtask terminal; PR open and mergeable. |
| `request_changes(task_id, findings)` | **Reject** a merge review: the subtask goes back to `needs_revision` with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}` — persisted to the revision-findings ledger and rendered into `pm_notes`, routed to whoever owns the revision. Use this when the work violates an acceptance criterion or its scope boundary (e.g. a commit touched files outside the task's declared scope) — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. `issues=['...']` still works this release but is deprecated. | Subtask in `awaiting_pm_review`; at least one finding; journal `decision` recorded. |
| `request_changes(task_id, findings)` | **Reject** a merge review: the subtask goes back to `needs_revision` with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; **field caps: `file`/`expected`/`actual` ≤300 chars, `criterion`/`fix` ≤500, `evidence` ≤2000 — keep each terse, put detail in `evidence` not `actual` (oversized fields are rejected "malformed")** — persisted to the revision-findings ledger and rendered into `pm_notes`, routed to whoever owns the revision. Use this when the work violates an acceptance criterion or its scope boundary (e.g. a commit touched files outside the task's declared scope) — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. `issues=['...']` still works this release but is deprecated. | Subtask in `awaiting_pm_review`; at least one finding; journal `decision` recorded. |
| `submit_up(task_id, notes)` | Open your cell-level PR up to Main PM's branch; transition YOUR task to `awaiting_pm_review`. | All your subtasks terminal; `notes` >= 20 chars; journal `decision` recorded. |
| `escalate_up(task_id, reason)` | Escalate to Main PM. | Task is yours or assigned to your cell. |
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
+2 -2
View File
@@ -24,7 +24,7 @@ Your task's `description` and the `parent_context` chain that arrives via `evide
| Verb | What it does | Preconditions |
|---|---|---|
| `give_me_work()` | Returns your highest-priority task or `idle`. | None. |
| `i_will_work_on(task_id, plan, steps)` | Claims a `pending`/`needs_revision` task; resumes a `claimed`/`in_progress` task you own. Auto-creates branch on first claim. **`plan` is REQUIRED** (narrative; `tracing_gap missing=['plan']` if absent). **On a FRESH claim `steps` is REQUIRED and gated** — a non-empty list of `{title, description}` where every `description` is **≥60 chars** saying what that step actually does. `steps` is your execution checklist AND your progress checklist: as you finish each, call `progress(task_id, plan_step=<step id/order>, message=...)` and the % is computed from the checklist for you. Thin/title-only steps are rejected. Example step: `{"title": "Edit README", "description": "prepend the smoke-test HTML comment above the H1, leaving the rest of the file untouched"}`. **On resume** (`claimed`/`in_progress` you own) pass `plan='resume: <next step>'`; steps are not re-required. | Task assigned to you (or unassigned and matches your role/team); journal `decision` recorded; non-empty `plan`; substantive `steps` on fresh claim. |
| `i_will_work_on(task_id, plan, steps)` | Claims a `pending`/`needs_revision` task; resumes a `claimed`/`in_progress` task you own. Auto-creates branch on first claim. **`plan` is REQUIRED** (narrative; `tracing_gap missing=['plan']` if absent). **On a FRESH claim `steps` is REQUIRED and gated** — a non-empty list of `{title, description}` where every `description` is **≥60 chars** saying what that step actually does. `steps` is your execution checklist AND your progress checklist: as you finish each, call `progress(task_id, plan_step=<step id/order>, message=...)` and the % is computed from the checklist for you. Thin/title-only steps are rejected. **On a fresh claim `technical_considerations` (non-empty list[str]) and `risks` (list of `{risk, mitigation}`) are also REQUIRED** — the gateway rejects a fresh claim missing them (`incomplete_input`); pass them as separate kwargs, not inside `plan`. On resume they are not re-required. Example step: `{"title": "Edit README", "description": "prepend the smoke-test HTML comment above the H1, leaving the rest of the file untouched"}`. **On resume** (`claimed`/`in_progress` you own) pass `plan='resume: <next step>'`; steps are not re-required. | Task assigned to you (or unassigned and matches your role/team); journal `decision` recorded; non-empty `plan`; substantive `steps` on fresh claim. |
| `commit(message)` | Makes the git commit, auto-prefixes `[task-id]`, records a progress entry. This is the ONLY way to commit — the gateway covers the actual git operation. | Task in `in_progress`; on your branch. |
| `open_pr(task_id)` | Push your branch and open a PR. Run after your last commit, before `i_am_done`. `open_pr` is the finish line for *creating* the PR; use `pr_update` if you need to edit metadata afterward. | Task assigned to you; at least one commit; no PR yet. |
| `pr_update(task_id, title?, body?, reviewers?)` | Update an existing PR's title, body, or reviewer list. Use after `open_pr` if you need to correct title/body or assign a reviewer. At least one field must be set. **Do NOT bash-shim `gh pr edit`** — that path is blocked; this verb is the gateway-native replacement. | Task has `pr_number`; you are the assignee (or your PM). |
@@ -53,7 +53,7 @@ When you respawn, your task is in some lifecycle status. The next call follows f
| `claimed` (your prior claim is intact, work not yet started) | `i_will_work_on(task_id, plan='resume: <what you'll do next>')` — composes claim+set_plan+start; resumes from `claimed` into `in_progress` |
| `in_progress`, no commits yet | `evidence(task_id)` to confirm scope → start editing → `commit(message)` |
| `in_progress`, edits made, not yet tested | run tests via `Bash` → on green, `commit(message)` |
| `in_progress`, satisfied with the work | `note(scope='reflect', text='...')``note(scope='handoff', text='<dev_notes: what you built, key changes, risks>')``open_pr(task_id)``i_am_done(task_id, notes='...')` |
| `in_progress`, satisfied with the work | `note(scope='reflect', text='...')``note(scope='handoff', text='<dev_notes: what you built, key changes, risks>')``open_pr(task_id)` **`make quality` must pass locally first (run it after your last commit; fix every failure, including the markdown reflow check, before submitting)** → `i_am_done(task_id, notes='...')` |
| `needs_revision` (QA/PR-gate/PM/CEO bounced you) | `evidence(task_id)` to read `revision_findings` (the structured findings, not just `qa_notes` prose) → `note(scope='decision', text='fix plan: <what + why, per finding>')``i_will_work_on(task_id, plan='...')` → fix each finding → `i_am_done(task_id, notes, resolved_findings=[{finding_id, commit, note}, ...])` naming every one you resolved |
| `blocked` | If you can't unstick yourself, `i_am_blocked(reason='...')` and let your PM resolve it. Do NOT try other verbs on `blocked`. |
| `paused` | `resume(task_id)` (transitions paused → in_progress; only valid when you own a paused task) |
+1 -1
View File
@@ -57,7 +57,7 @@ This is the single most common mental-model mistake at your seat. Get it right:
| `triage_all()` | List blockers and reviews across all cells. | None. |
| `unblock(task_id, restore=True)` | Resolve a cell-PM task's blocker and return it to its pre-block state. | None. |
| `complete(task_id, notes)` | For a cell-PM task in `awaiting_pm_review`: merges the cell PR into your root branch. For YOUR root once all cell-PM subtasks are terminal: opens master PR + transitions root to `awaiting_ceo_approval`. | All descendants terminal; journal `decision` recorded. |
| `request_changes(task_id, findings)` | **Reject** a merge review: the cell-PM task goes back to `needs_revision` with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}` — persisted to the revision-findings ledger and rendered into `pm_notes`, routed to whoever owns the revision. Use for an AC/scope violation caught at review — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. `issues=['...']` still works this release but is deprecated. | Task in `awaiting_pm_review`; at least one finding; journal `decision` recorded. |
| `request_changes(task_id, findings)` | **Reject** a merge review: the cell-PM task goes back to `needs_revision` with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; **field caps: `file`/`expected`/`actual` ≤300 chars, `criterion`/`fix` ≤500, `evidence` ≤2000 — keep each terse, put detail in `evidence` not `actual` (oversized fields are rejected "malformed")** — persisted to the revision-findings ledger and rendered into `pm_notes`, routed to whoever owns the revision. Use for an AC/scope violation caught at review — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. `issues=['...']` still works this release but is deprecated. | Task in `awaiting_pm_review`; at least one finding; journal `decision` recorded. |
| `escalate_up(task_id, reason)` | Escalate a stuck task up your chain to CEO. | Task is yours or assigned to a cell under your scope. |
| `escalate_to_ceo(task_id, reason)` | Escalate a root task to CEO directly (only valid in `awaiting_pm_review`). | Root task in `awaiting_pm_review`; `pr_number` set. |
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
+1 -1
View File
@@ -25,7 +25,7 @@ The PR is from an outside contributor: its code is **untrusted**. Until a human
| `post_pr_review(task_id, body, findings=[...])` | Posts ONE complete change-request and finishes the review. `in_progress → completed`. `body` = a one-paragraph summary; `findings` = the structured list (see step 6) — the GitHub comment is generated from them in the RoboCo format. | Task claimed by you; findings cover every relevant criterion. |
| `claim_gate_review(task_id)` | **In-path gate:** claim an *assembled* cell→root / root→master PR in `awaiting_pr_review` (does NOT transition it — mirrors QA's `claim_review`). Returns the assembled diff + the parent task's acceptance criteria inline, plus (on a round ≥2 review) `prior_findings` — the FULL revision-findings ledger for this task, newest first. Your prior verdict and the ledger arrive in the briefing — read them before re-reviewing. | Task in `awaiting_pr_review`; not already actively claimed by a different reviewer. |
| `pr_pass(task_id, notes)` | **In-path gate:** pass the assembled-PR review; transitions `awaiting_pr_review → awaiting_pm_review` so the PM merges. Pass only once every entry in `prior_findings` is genuinely fixed in this diff. | Task claimed by you via `claim_gate_review`; `notes` >= 20 chars. |
| `pr_fail(task_id, findings)` | **In-path gate:** fail the assembled-PR review with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; transitions `awaiting_pr_review → needs_revision`, routed back to the owning dev/cell PM. Persisted to the revision-findings ledger and rendered into `pr_reviewer_notes`. Nudge above 5 findings, hard reject above 10. `issues=['...']` still works this release but is deprecated. | Task claimed by you via `claim_gate_review`; at least one finding. |
| `pr_fail(task_id, findings)` | **In-path gate:** fail the assembled-PR review with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; **field caps: `file`/`expected`/`actual` ≤300 chars, `criterion`/`fix` ≤500, `evidence` ≤2000 — keep each terse, put detail in `evidence` not `actual` (oversized fields are rejected "malformed")**; transitions `awaiting_pr_review → needs_revision`, routed back to the owning dev/cell PM. Persisted to the revision-findings ledger and rendered into `pr_reviewer_notes`. Nudge above 5 findings, hard reject above 10. `issues=['...']` still works this release but is deprecated. | Task claimed by you via `claim_gate_review`; at least one finding. |
| `note(text, scope?)` | Journal entry. Record your reasoning. | None. |
| `evidence(task_id)` | Re-fetch the PR diff if you need more detail. | None. |
| `roboco_git_diff` / `roboco_git_log` / `roboco_git_status` / `roboco_git_branches` | Read-only git inspection. | None. |
+1 -1
View File
@@ -20,7 +20,7 @@ A pass without evidence is a betrayal of your role: the entire downstream chain
| `give_me_work()` | Returns a task in `awaiting_qa` for your team or `idle`. | None. |
| `claim_review(task_id)` | Claims the QA task; returns PR data inline. | Task in `awaiting_qa`; you are not the original developer. |
| `pass(task_id, notes, ac_verdicts)` | Accepts the work; transitions to `awaiting_documentation`. `ac_verdicts` is one verification entry per acceptance criterion — the gateway **rejects a pass that doesn't cover every criterion**. | Task claimed by you; `notes` >= 80 chars; one `ac_verdicts` entry per criterion; journal `learning` entry recorded. |
| `fail(task_id, findings)` | Rejects with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; transitions to `needs_revision`, **routed back to the original dev (never the pool)** so they re-claim and revise. `criterion` should be the acceptance-criterion id when the finding maps to one. Persisted to the revision-findings ledger and rendered into `qa_notes`. Nudge above 5 findings, hard reject above 10 — split or prioritize. `issues=['...']` (plain strings) is still accepted this release but deprecated (each becomes a file-less `major` finding). | Task claimed by you; at least one finding. |
| `fail(task_id, findings)` | Rejects with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}`; **field caps: `file`/`expected`/`actual` ≤300 chars, `criterion`/`fix` ≤500, `evidence` ≤2000 — keep each terse, put detail in `evidence` not `actual` (oversized fields are rejected "malformed")**; transitions to `needs_revision`, **routed back to the original dev (never the pool)** so they re-claim and revise. `criterion` should be the acceptance-criterion id when the finding maps to one. Persisted to the revision-findings ledger and rendered into `qa_notes`. Nudge above 5 findings, hard reject above 10 — split or prioritize. `issues=['...']` (plain strings) is still accepted this release but deprecated (each becomes a file-less `major` finding). | Task claimed by you; at least one finding. |
| `i_am_blocked(task_id, reason, blocker_type?, what_needed?)` | Record a blocker, escalate to your PM, idle. `blocker_type``external`/`internal`/`question`/`dependency`; `what_needed` is a one-sentence concrete unblock request. Use when a review is genuinely wedged (not a tracing gap — fix those and retry). | Task is yours and active. |
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
| `resume(task_id)` | Resume a paused task. Transitions paused → in_progress. | Task assigned to you and in paused state. |