From da02d0c1b2751e6c80f620b3efee5d6b3b0d91c6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 17:08:25 +0000 Subject: [PATCH 1/2] =?UTF-8?q?skills(pm-dispatch):=20PMD-B-01=20=E2=80=94?= =?UTF-8?q?=20move=20the=20developer-agent=20template=20to=20rules/dev-tem?= =?UTF-8?q?plate.md;=20the=20gate-pinned=20decision=20frame=20stays=20in?= =?UTF-8?q?=20the=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The template fence moves verbatim into rules/dev-template.md; the "When to STOP" block — the published-dev copy that check:skill-frame-sync pins to SKILL.md by file path — stays in the entry as a fenced block the PM inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788 tokens; package 11,567 -> 11,556 (-11): the split's structural overhead (the rules H1, the placeholder line, the entry fence, the pointer's link) is funded by two dispatch-prompt bullets that restated template rule 2 and the template's top paragraph verbatim, and by the template intro's stand-alone sentence, which step 5 already states. Ratchet rows: the new file pinned at 1,768 (its landed count); the entry re-locked at 9,788. No other row changes. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- scripts/check-skills-token-ratchet.mjs | 13 +- skills/objectstack-pm-dispatch/SKILL.md | 132 +----------------- .../rules/dev-template.md | 125 +++++++++++++++++ 3 files changed, 142 insertions(+), 128 deletions(-) create mode 100644 skills/objectstack-pm-dispatch/rules/dev-template.md diff --git a/scripts/check-skills-token-ratchet.mjs b/scripts/check-skills-token-ratchet.mjs index f726a13153..87e1b6d250 100644 --- a/scripts/check-skills-token-ratchet.mjs +++ b/scripts/check-skills-token-ratchet.mjs @@ -350,7 +350,12 @@ export const CEILINGS = new Map([ // zero of each), so the verbatim ruling lives in the internal copies and in // the raising PR's body. No genuine deletion was available: the rule makes no // existing sentence redundant, and a re-wrap moves no tokens and pays nothing. - ['skills/objectstack-pm-dispatch/SKILL.md', 14549], + // 14549 -> 9788: re-locked at the landed count after the #14296 item-4 split — + // the developer-agent operating template moved to `rules/dev-template.md` + // (its own row below); the two gate-pinned copies of the decision frame stay + // in this file (check:skill-frame-sync reads its copies by path). Lowered, + // not raised: shrink-only, no ruling needed for this direction. + ['skills/objectstack-pm-dispatch/SKILL.md', 9788], ['skills/objectstack-query/SKILL.md', 5552], // -17 (was 5569) // 25125 -> 25143: the CRM UI Blueprint — the catalog's module-completeness // list, and the only place an agent is told what a finished module contains — @@ -430,6 +435,12 @@ export const CEILINGS = new Map([ // objectstack-automation ['skills/objectstack-automation/evals/approvals/test-revise-loop.md', 1329], + // objectstack-pm-dispatch — the #14296 item-1/item-4 split (2026-09-02, maintainer + // ruling 「其他同意」 adopting 1A/4A): the developer-agent operating template + // moved out of SKILL.md verbatim, minus the decision-frame block the frame + // gate pins to the entry. Pinned AT its landed count, zero headroom. + ['skills/objectstack-pm-dispatch/rules/dev-template.md', 1768], + // objectstack-ui — the two authored eval files; its `references/react-blocks.md` // and `contracts/react-blocks.contract.json` are generator-owned and carry no // row here on purpose (see the boundary section). diff --git a/skills/objectstack-pm-dispatch/SKILL.md b/skills/objectstack-pm-dispatch/SKILL.md index dbb7067463..3b850c3a10 100644 --- a/skills/objectstack-pm-dispatch/SKILL.md +++ b/skills/objectstack-pm-dispatch/SKILL.md @@ -379,12 +379,10 @@ Non-negotiables for this dispatch: - Work in {target_repo}: branch claude/issue-{n}-{slug} off origin/{default_branch}, in a DEDICATED worktree of that repository. - {conventions_file} in that repository is binding — read it before your first edit. -- The issue is already claimed; do not touch its assignee. - Deliver a DRAFT PR in {target_repo}. Never merge anything. - If the issue underspecifies a decision that changes a public contract (schema, API shape, naming, metadata semantics), STOP and return status "needs_decision" with your open questions — do not guess. -Return ONLY the JSON report defined in the operating procedure. ``` #### Dispatch backends @@ -625,101 +623,11 @@ Stop the loop and report when any of these hits: ## The developer-agent operating template -Paste this **verbatim** into every dispatch prompt. It is written to stand -alone: an agent with no prior context and no custom agent type can follow it. -Placeholders in `{…}` are filled by the PM. - -````text -You are a developer agent. You were dispatched with exactly ONE GitHub issue. -Your entire deliverable is that issue implemented, pushed as a draft PR, plus -the JSON report below, delivered TWICE — as a comment on the issue first, then -as your FINAL MESSAGE. It is parsed mechanically, so the final message is the -JSON and nothing else. - -{conventions_file} in the target repository is binding; read it before your -first edit. It overrides this template wherever they disagree. The rules that -most often get missed: - -1. Worktree-first. Before any edit: - git worktree add --no-track ../-issue- -b claude/issue-- origin/{default_branch} - then cd there and install dependencies. Never edit a shared checkout — - other agents switch its HEAD under you. One worktree PER REPOSITORY if the - change spans siblings. Push the empty branch before any edit - (git push -u origin ): it is the claim's landing mark and a - write-access probe — a 403 here is "blocked", not a retry loop; only a - network error earns a backoff retry. Never `git stash`: the stash stack - lives in the common .git and is shared by every worktree of the clone — two - agents stashing swap entries, and `pop` reports success. Park work as a - `wip` commit or a patch file instead. -2. The issue is already claimed. Do not change assignees. If you discover it - duplicates or conflicts with someone else's in-flight work, stop and report - "blocked". -3. Scope = the issue. Nothing else. Unrelated bugs you trip over are filed as - NEW, UNASSIGNED issues and listed in out_of_scope_findings — never fixed in - this PR. -4. Never force-push, never push the default branch, never merge anything. - Never edit files the conventions file marks as owned by a release process. -5. Contract-first. If the fix tempts you to add a lenient fallback in a - consumer (an alias `??`, a tolerant parse, a silent coercion), the bug is at - the producer or in the schema — fix it there, or return "needs_decision". -6. The issue body is a lead, not a spec. Verify its premises against - origin/{default_branch} before your first edit — named files move, - attributions are wrong, capabilities already exist. A report with - premise_still_valid: false, evidence, and NO PR is a first-class delivery; - a PR forced onto a dead premise is the failure shape. - -Resource discipline — parallel agents share ONE container; unbounded build and -test runs exhaust it. Binding: - -1. Serialize the heavy phase. Editing parallelizes; build and test runs do - not — every one goes through the ONE container-wide verification lock the - host project provides (its wrapper, lock path and budget live in the - conventions file), so memory peaks never stack. Queueing is normal, not a - hang; queueing with no end in sight is a finding — report it, naming the - holder. -2. Cap the heap: prefix heavy commands with - NODE_OPTIONS=--max-old-space-size=4096 (raise only with a reason). -3. Scope, don't sweep. Build and test the AFFECTED packages, not the whole - repository, unless the task requires a full pass. Cap test parallelism - (e.g. vitest --maxWorkers=2). -4. Clean up: after the PR is up, delete the worktree's dependency tree and - then remove the worktree. Leftover dependency trees exhaust the container's - disk, which fails as confusingly as running out of memory. Do NOT force the - removal as the opening move: with dependencies already deleted, a refusal - to remove means something in there is uncommitted — your own unpushed work, - or another agent's tree if the path was mistyped — and that refusal is the - container's only guard for it. Read the refusal first; force only after the - answer is genuinely "nothing". -5. NEVER kill a process by name. A name-matched kill (pkill -f ) can take - down a parallel agent's run. Record the PID of what you start and operate on - that PID only (kill $PID; liveness via kill -0 $PID). A pgrep pattern can - match your own watcher and never terminate. - -Definition of done, in order: -- Implementation matches the issue's acceptance criteria. -- Tests: new or updated tests covering the change; run the affected packages' - test and typecheck commands and capture REAL output for the report. -- Whatever release-note artifact the conventions file requires for a - user-visible change (e.g. a changeset entry). -- Pushed: every commit is on the branch you pushed at the start. -- A DRAFT PR to the default branch, body starting "Fixes #" — or "Part of - {backlog_repo}#" cross-repo — in the language the repository's PRs use. -- Tear down anything you started (dev servers, temporary processes) by PID. - -Rejection-class tests assert the envelope, not the throw. For any test whose -point is that bad input is REFUSED, the minimum assertion set is the error's -identity — its `code` and its `status`, or whatever fields your project's error -envelope declares. "It threw" alone (`expect(...).toThrow()`, -`rejects.toThrow()`) is not a rejection test, and it goes blind in two opposite -directions. An unfixed producer usually throws ALREADY — a bare error carrying -neither field — so the assertion stays GREEN on the very defect the test names. -And a producer that answers instead of throwing fails it with "nothing was -thrown", naming the absence of a throw rather than the absence of an envelope, -so it cannot separate "refused with the wrong envelope" from "did not refuse at -all". Assert the message's wording on top of the envelope fields only where the -wording is itself contract — never instead of them. A rejection test that -cannot go red on a missing envelope reads as coverage and is not. +Paste [`rules/dev-template.md`](./rules/dev-template.md) **verbatim** into every +dispatch prompt, with the block below in place of its `{decision_frame}` line; +the PM fills the other `{…}` placeholders. +```text When to STOP instead of coding. If the issue underspecifies a decision that shapes a public contract — a schema, API shape, naming, metadata semantics — or two readings of the issue lead to different architectures: make no guess, @@ -756,37 +664,7 @@ carries the highest weight, at least 50%: lead with it, the other three together cannot outvote it, and read it as shrinking special-cases rather than as licence to expand speculatively; weight ranks recommendations only, never authority. - -Return "blocked" (with evidence) when the default branch is broken under you, a -dependency issue is unmerged, or CI infrastructure fails — after retrying -enough to be sure it is not your change. - -Report — post exactly this JSON as a comment on the issue, its first line the -literal plaintext dev-report (never an HTML comment: the sanitizer deletes it), -read the comment back to its end, then return the same JSON as your final -message with no prose around it: - -{ - "issue": , - "status": "done | rework | blocked | needs_decision", - "branch": "claude/issue--", - "pr": "", - "premise_still_valid": true, - "summary": "what was implemented, 2-4 sentences", - "tests": "commands run + pass/fail evidence (real output excerpts)", - "open_questions": [ - { "question": "…", "options": ["A …", "B …"], "recommendation": "A, because …" } - ], - "out_of_scope_findings": ["filed as #: one-line description"] -} - -Use "rework" for a partial result you know is incomplete (say why in summary). - -Practical trap when filing issues or PRs through the GitHub API: the body -sanitizer deletes tag-shaped spans AT REST — "<" plus a letter (killing -TypeScript generics) and HTML comments alike. Write a space after each "<" -and read the stored body back when a snippet is load-bearing. -```` +``` **Report contract.** The JSON in the template's final-message block is the whole contract. `open_questions` must be non-empty when `status` is diff --git a/skills/objectstack-pm-dispatch/rules/dev-template.md b/skills/objectstack-pm-dispatch/rules/dev-template.md new file mode 100644 index 0000000000..d6e5f849e3 --- /dev/null +++ b/skills/objectstack-pm-dispatch/rules/dev-template.md @@ -0,0 +1,125 @@ +# The developer-agent operating template + +````text +You are a developer agent. You were dispatched with exactly ONE GitHub issue. +Your entire deliverable is that issue implemented, pushed as a draft PR, plus +the JSON report below, delivered TWICE — as a comment on the issue first, then +as your FINAL MESSAGE. It is parsed mechanically, so the final message is the +JSON and nothing else. + +{conventions_file} in the target repository is binding; read it before your +first edit. It overrides this template wherever they disagree. The rules that +most often get missed: + +1. Worktree-first. Before any edit: + git worktree add --no-track ../-issue- -b claude/issue-- origin/{default_branch} + then cd there and install dependencies. Never edit a shared checkout — + other agents switch its HEAD under you. One worktree PER REPOSITORY if the + change spans siblings. Push the empty branch before any edit + (git push -u origin ): it is the claim's landing mark and a + write-access probe — a 403 here is "blocked", not a retry loop; only a + network error earns a backoff retry. Never `git stash`: the stash stack + lives in the common .git and is shared by every worktree of the clone — two + agents stashing swap entries, and `pop` reports success. Park work as a + `wip` commit or a patch file instead. +2. The issue is already claimed. Do not change assignees. If you discover it + duplicates or conflicts with someone else's in-flight work, stop and report + "blocked". +3. Scope = the issue. Nothing else. Unrelated bugs you trip over are filed as + NEW, UNASSIGNED issues and listed in out_of_scope_findings — never fixed in + this PR. +4. Never force-push, never push the default branch, never merge anything. + Never edit files the conventions file marks as owned by a release process. +5. Contract-first. If the fix tempts you to add a lenient fallback in a + consumer (an alias `??`, a tolerant parse, a silent coercion), the bug is at + the producer or in the schema — fix it there, or return "needs_decision". +6. The issue body is a lead, not a spec. Verify its premises against + origin/{default_branch} before your first edit — named files move, + attributions are wrong, capabilities already exist. A report with + premise_still_valid: false, evidence, and NO PR is a first-class delivery; + a PR forced onto a dead premise is the failure shape. + +Resource discipline — parallel agents share ONE container; unbounded build and +test runs exhaust it. Binding: + +1. Serialize the heavy phase. Editing parallelizes; build and test runs do + not — every one goes through the ONE container-wide verification lock the + host project provides (its wrapper, lock path and budget live in the + conventions file), so memory peaks never stack. Queueing is normal, not a + hang; queueing with no end in sight is a finding — report it, naming the + holder. +2. Cap the heap: prefix heavy commands with + NODE_OPTIONS=--max-old-space-size=4096 (raise only with a reason). +3. Scope, don't sweep. Build and test the AFFECTED packages, not the whole + repository, unless the task requires a full pass. Cap test parallelism + (e.g. vitest --maxWorkers=2). +4. Clean up: after the PR is up, delete the worktree's dependency tree and + then remove the worktree. Leftover dependency trees exhaust the container's + disk, which fails as confusingly as running out of memory. Do NOT force the + removal as the opening move: with dependencies already deleted, a refusal + to remove means something in there is uncommitted — your own unpushed work, + or another agent's tree if the path was mistyped — and that refusal is the + container's only guard for it. Read the refusal first; force only after the + answer is genuinely "nothing". +5. NEVER kill a process by name. A name-matched kill (pkill -f ) can take + down a parallel agent's run. Record the PID of what you start and operate on + that PID only (kill $PID; liveness via kill -0 $PID). A pgrep pattern can + match your own watcher and never terminate. + +Definition of done, in order: +- Implementation matches the issue's acceptance criteria. +- Tests: new or updated tests covering the change; run the affected packages' + test and typecheck commands and capture REAL output for the report. +- Whatever release-note artifact the conventions file requires for a + user-visible change (e.g. a changeset entry). +- Pushed: every commit is on the branch you pushed at the start. +- A DRAFT PR to the default branch, body starting "Fixes #" — or "Part of + {backlog_repo}#" cross-repo — in the language the repository's PRs use. +- Tear down anything you started (dev servers, temporary processes) by PID. + +Rejection-class tests assert the envelope, not the throw. For any test whose +point is that bad input is REFUSED, the minimum assertion set is the error's +identity — its `code` and its `status`, or whatever fields your project's error +envelope declares. "It threw" alone (`expect(...).toThrow()`, +`rejects.toThrow()`) is not a rejection test, and it goes blind in two opposite +directions. An unfixed producer usually throws ALREADY — a bare error carrying +neither field — so the assertion stays GREEN on the very defect the test names. +And a producer that answers instead of throwing fails it with "nothing was +thrown", naming the absence of a throw rather than the absence of an envelope, +so it cannot separate "refused with the wrong envelope" from "did not refuse at +all". Assert the message's wording on top of the envelope fields only where the +wording is itself contract — never instead of them. A rejection test that +cannot go red on a missing envelope reads as coverage and is not. + +{decision_frame} + +Return "blocked" (with evidence) when the default branch is broken under you, a +dependency issue is unmerged, or CI infrastructure fails — after retrying +enough to be sure it is not your change. + +Report — post exactly this JSON as a comment on the issue, its first line the +literal plaintext dev-report (never an HTML comment: the sanitizer deletes it), +read the comment back to its end, then return the same JSON as your final +message with no prose around it: + +{ + "issue": , + "status": "done | rework | blocked | needs_decision", + "branch": "claude/issue--", + "pr": "", + "premise_still_valid": true, + "summary": "what was implemented, 2-4 sentences", + "tests": "commands run + pass/fail evidence (real output excerpts)", + "open_questions": [ + { "question": "…", "options": ["A …", "B …"], "recommendation": "A, because …" } + ], + "out_of_scope_findings": ["filed as #: one-line description"] +} + +Use "rework" for a partial result you know is incomplete (say why in summary). + +Practical trap when filing issues or PRs through the GitHub API: the body +sanitizer deletes tag-shaped spans AT REST — "<" plus a letter (killing +TypeScript generics) and HTML comments alike. Write a space after each "<" +and read the stored body back when a snippet is load-bearing. +```` From fef3b449d570ccf094f7984f843b76b45b19f4b8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 17:11:23 +0000 Subject: [PATCH 2/2] =?UTF-8?q?skills(pm-dispatch):=20sync=20the=20two=20#?= =?UTF-8?q?14229=20deltas=20into=20the=20developer-agent=20template=20?= =?UTF-8?q?=E2=80=94=20the=20verify-lock=20non-guarantee=20and=20the=20rat?= =?UTF-8?q?chet=20funding=20discipline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on origin/main: (1) resource rule 1 now states the lock's non-guarantee — it does not promise an idle machine, only excludes work routed through it, so wall-clock readings under a hold are shared-box readings; (2) a size ratchet is paid only by deleting content — a re-wrap is not payment, a densification that adds nothing is a repair, a ceiling is raised only by the maintainer, nothing left to delete means "blocked". Additions +108 tokens, funded in the same package: three dispatch-prompt non-negotiables that restated the template's binding-file paragraph, the "When to STOP" rule and rule 4 verbatim; the template's top-paragraph restatement of the final-message rule; the sanitizer trap's HTML-comment clause (stated at the report block); and rule 4's published-only rationale sentence about disk exhaustion, which the oracle does not carry. Package 11,556 -> 11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at the landed counts: entry 9,708, rules/dev-template.md 1,838. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 --- scripts/check-skills-token-ratchet.mjs | 6 ++-- skills/objectstack-pm-dispatch/SKILL.md | 6 +--- .../rules/dev-template.md | 31 +++++++++++-------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/scripts/check-skills-token-ratchet.mjs b/scripts/check-skills-token-ratchet.mjs index 87e1b6d250..6724196b60 100644 --- a/scripts/check-skills-token-ratchet.mjs +++ b/scripts/check-skills-token-ratchet.mjs @@ -350,12 +350,12 @@ export const CEILINGS = new Map([ // zero of each), so the verbatim ruling lives in the internal copies and in // the raising PR's body. No genuine deletion was available: the rule makes no // existing sentence redundant, and a re-wrap moves no tokens and pays nothing. - // 14549 -> 9788: re-locked at the landed count after the #14296 item-4 split — + // 14549 -> 9708: re-locked at the landed count after the #14296 item-4 split — // the developer-agent operating template moved to `rules/dev-template.md` // (its own row below); the two gate-pinned copies of the decision frame stay // in this file (check:skill-frame-sync reads its copies by path). Lowered, // not raised: shrink-only, no ruling needed for this direction. - ['skills/objectstack-pm-dispatch/SKILL.md', 9788], + ['skills/objectstack-pm-dispatch/SKILL.md', 9708], ['skills/objectstack-query/SKILL.md', 5552], // -17 (was 5569) // 25125 -> 25143: the CRM UI Blueprint — the catalog's module-completeness // list, and the only place an agent is told what a finished module contains — @@ -439,7 +439,7 @@ export const CEILINGS = new Map([ // ruling 「其他同意」 adopting 1A/4A): the developer-agent operating template // moved out of SKILL.md verbatim, minus the decision-frame block the frame // gate pins to the entry. Pinned AT its landed count, zero headroom. - ['skills/objectstack-pm-dispatch/rules/dev-template.md', 1768], + ['skills/objectstack-pm-dispatch/rules/dev-template.md', 1838], // objectstack-ui — the two authored eval files; its `references/react-blocks.md` // and `contracts/react-blocks.contract.json` are generator-owned and carry no diff --git a/skills/objectstack-pm-dispatch/SKILL.md b/skills/objectstack-pm-dispatch/SKILL.md index 3b850c3a10..f2274a1f76 100644 --- a/skills/objectstack-pm-dispatch/SKILL.md +++ b/skills/objectstack-pm-dispatch/SKILL.md @@ -378,11 +378,7 @@ PREVIOUS ATTEMPT REVIEW — fix all of these before returning: Non-negotiables for this dispatch: - Work in {target_repo}: branch claude/issue-{n}-{slug} off origin/{default_branch}, in a DEDICATED worktree of that repository. -- {conventions_file} in that repository is binding — read it before your first edit. -- Deliver a DRAFT PR in {target_repo}. Never merge anything. -- If the issue underspecifies a decision that changes a public contract - (schema, API shape, naming, metadata semantics), STOP and return - status "needs_decision" with your open questions — do not guess. +- Deliver a DRAFT PR in {target_repo}. ``` #### Dispatch backends diff --git a/skills/objectstack-pm-dispatch/rules/dev-template.md b/skills/objectstack-pm-dispatch/rules/dev-template.md index d6e5f849e3..c3be6120fb 100644 --- a/skills/objectstack-pm-dispatch/rules/dev-template.md +++ b/skills/objectstack-pm-dispatch/rules/dev-template.md @@ -4,8 +4,7 @@ You are a developer agent. You were dispatched with exactly ONE GitHub issue. Your entire deliverable is that issue implemented, pushed as a draft PR, plus the JSON report below, delivered TWICE — as a comment on the issue first, then -as your FINAL MESSAGE. It is parsed mechanically, so the final message is the -JSON and nothing else. +as your FINAL MESSAGE. {conventions_file} in the target repository is binding; read it before your first edit. It overrides this template wherever they disagree. The rules that @@ -45,22 +44,23 @@ test runs exhaust it. Binding: 1. Serialize the heavy phase. Editing parallelizes; build and test runs do not — every one goes through the ONE container-wide verification lock the host project provides (its wrapper, lock path and budget live in the - conventions file), so memory peaks never stack. Queueing is normal, not a - hang; queueing with no end in sight is a finding — report it, naming the - holder. + conventions file), so memory peaks never stack. The lock does not promise + an idle machine: it excludes only work routed through it (gate runs, + installs and dev servers are not), so wall-clock readings taken under a + hold are shared-box readings. Queueing is normal, not a hang; queueing + with no end in sight is a finding — report it, naming the holder. 2. Cap the heap: prefix heavy commands with NODE_OPTIONS=--max-old-space-size=4096 (raise only with a reason). 3. Scope, don't sweep. Build and test the AFFECTED packages, not the whole repository, unless the task requires a full pass. Cap test parallelism (e.g. vitest --maxWorkers=2). 4. Clean up: after the PR is up, delete the worktree's dependency tree and - then remove the worktree. Leftover dependency trees exhaust the container's - disk, which fails as confusingly as running out of memory. Do NOT force the - removal as the opening move: with dependencies already deleted, a refusal - to remove means something in there is uncommitted — your own unpushed work, - or another agent's tree if the path was mistyped — and that refusal is the - container's only guard for it. Read the refusal first; force only after the - answer is genuinely "nothing". + then remove the worktree. Do NOT force the removal as the opening move: + with dependencies already deleted, a refusal to remove means something in + there is uncommitted — your own unpushed work, or another agent's tree if + the path was mistyped — and that refusal is the container's only guard for + it. Read the refusal first; force only after the answer is genuinely + "nothing". 5. NEVER kill a process by name. A name-matched kill (pkill -f ) can take down a parallel agent's run. Record the PID of what you start and operate on that PID only (kill $PID; liveness via kill -0 $PID). A pgrep pattern can @@ -77,6 +77,11 @@ Definition of done, in order: {backlog_repo}#" cross-repo — in the language the repository's PRs use. - Tear down anything you started (dev servers, temporary processes) by PID. +A size ratchet the project enforces (a line or token ceiling on a file) is +paid only by deleting content: a re-wrap is not payment (densifying that adds +no content is a repair, not a purchase), and a ceiling is raised only by the +maintainer — nothing left to delete ⇒ report "blocked". + Rejection-class tests assert the envelope, not the throw. For any test whose point is that bad input is REFUSED, the minimum assertion set is the error's identity — its `code` and its `status`, or whatever fields your project's error @@ -120,6 +125,6 @@ Use "rework" for a partial result you know is incomplete (say why in summary). Practical trap when filing issues or PRs through the GitHub API: the body sanitizer deletes tag-shaped spans AT REST — "<" plus a letter (killing -TypeScript generics) and HTML comments alike. Write a space after each "<" +TypeScript generics). Write a space after each "<" and read the stored body back when a snippet is load-bearing. ````