From 6cefbb070e3a730d61ceb37858605d27e75e8a81 Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 15 May 2026 14:47:54 +0000 Subject: [PATCH 1/4] fix(#157): add S9 invariant and never-close constraint to dev-loop spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add S9 to §6 Safety Invariants: zero close-PR API calls in dispatch - Document worker ABSOLUTE CONSTRAINTS in §8 Worker Templates - Add §9 entry for Issue #157 explaining the fix All worker templates already contain the NEVER-close constraint from a prior session. This commit makes the spec authoritative. Companion changes in rodin/workspace: - check-invariants.sh: add S9 static check - dispatch.bats: add Bug-157-regression test --- docs/dev-loop-spec.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/dev-loop-spec.md b/docs/dev-loop-spec.md index 226b511..041383a 100644 --- a/docs/dev-loop-spec.md +++ b/docs/dev-loop-spec.md @@ -231,6 +231,7 @@ These are statically checked by `~/.openclaw/workspace/scripts/test/check-invari | S6 | Active WIP does not cause early exit (only sets ACTIVE_WIP flag) | | S7 | SPAWN:impl guarded by `ACTIVE_WIP == 0` check | | S8 | No merge calls in any worker template | +| S9 | Zero close-PR API calls in dispatch script (`state=closed` does not appear) | --- @@ -263,9 +264,20 @@ Each worker receives a precise task description with substituted values: Workers **always** remove the WIP label on completion and reply `NO_REPLY`. +### Worker Absolute Constraints + +Every worker template begins with an `⛔ ABSOLUTE CONSTRAINTS` section containing these rules: + +- **NEVER close a PR.** Never call `PATCH /pulls/{id}` with `state=closed`. Closing a PR requires human action. "Duplicate", "superseded", or "already done" are never a worker's call. +- **NEVER merge a PR.** Never call the merge API. Merging requires human approval. +- **NEVER use the gitea-aweiker token.** All API calls use the gitea-rodin token only. +- **NEVER act on a PR with active REQUEST_CHANGES.** Fix the findings first. + +These constraints are enforced by S1, S8, and S9 in `check-invariants.sh` (for the dispatch script) and by the template text itself (for workers). + --- -## 9. Fixes for Issues #144 and #145 +## 9. Fixes for Issues #144, #145, and #157 **Issue #144** (autonomous merge): The dispatch script contains no merge API calls anywhere. The `~/.openclaw/workspace/scripts/test/check-invariants.sh` @@ -276,3 +288,11 @@ Rule 2 is the **first** rule evaluated per PR. It cannot be skipped, reasoned pa or bypassed. It is checked before CI, before self-review, before handoff. The check uses latest-per-reviewer state, so a reviewer who re-approved after REQUEST_CHANGES is correctly handled. + +**Issue #157** (autonomous PR close): +Worker templates were missing an explicit constraint against closing PRs. The dispatch +script never had a close call, but workers could reason their way into calling +`PATCH /pulls/{id}` with `state=closed`. All worker templates now include +`NEVER close a PR` in their ABSOLUTE CONSTRAINTS section. Invariant S9 verifies +the dispatch script contains no close calls. The regression test in `dispatch.bats` +verifies the same statically. -- 2.47.3 From fb7d8d5e3bb47385cae9b17e9d5ba0313fbd1eb4 Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 15 May 2026 10:26:14 -0700 Subject: [PATCH 2/4] =?UTF-8?q?fix(#158):=20add=20S10=20invariant=20to=20s?= =?UTF-8?q?pec,=20fix=20enforcement=20wording=20in=20=C2=A78?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address MINOR and NIT findings from Sonnet and GPT review of PR #158. MINOR (Sonnet + GPT): No static invariant for 'no close-PR in worker templates'. - Add S10 to §6 Safety Invariants table: checks that no worker template contains close-PR API calls AND every template contains NEVER-close constraint text. - Symmetric to S8 (no merge in worker templates) and S9 (no close in dispatch). NIT (GPT): Enforcement mapping sentence in §8 was ambiguous. - Rewrite to explicitly map: S1+S9 cover dispatch; S8+S10 cover worker templates. NIT (Sonnet): The 'all 7 templates contain NEVER-close text' claim is now verified by S10 (grep-based), not just prose. Implementation: S10 added to check-invariants.sh + Bug-157-S10 regression tests added to dispatch.bats (in rodin/workspace). All 11 invariants pass. --- docs/dev-loop-spec.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/dev-loop-spec.md b/docs/dev-loop-spec.md index 041383a..670f276 100644 --- a/docs/dev-loop-spec.md +++ b/docs/dev-loop-spec.md @@ -232,6 +232,7 @@ These are statically checked by `~/.openclaw/workspace/scripts/test/check-invari | S7 | SPAWN:impl guarded by `ACTIVE_WIP == 0` check | | S8 | No merge calls in any worker template | | S9 | Zero close-PR API calls in dispatch script (`state=closed` does not appear) | +| S10 | No close-PR API calls in any worker template; every worker template contains `NEVER close a PR` | --- @@ -273,7 +274,7 @@ Every worker template begins with an `⛔ ABSOLUTE CONSTRAINTS` section containi - **NEVER use the gitea-aweiker token.** All API calls use the gitea-rodin token only. - **NEVER act on a PR with active REQUEST_CHANGES.** Fix the findings first. -These constraints are enforced by S1, S8, and S9 in `check-invariants.sh` (for the dispatch script) and by the template text itself (for workers). +These constraints are statically enforced by `check-invariants.sh`: S1 and S9 cover the dispatch script (no merge, no close); S8 and S10 cover worker templates (no merge calls, no close calls, and NEVER-close text present in each). --- @@ -294,5 +295,6 @@ Worker templates were missing an explicit constraint against closing PRs. The di script never had a close call, but workers could reason their way into calling `PATCH /pulls/{id}` with `state=closed`. All worker templates now include `NEVER close a PR` in their ABSOLUTE CONSTRAINTS section. Invariant S9 verifies -the dispatch script contains no close calls. The regression test in `dispatch.bats` -verifies the same statically. +the dispatch script contains no close calls. Invariant S10 verifies +worker templates contain no close calls and each contains the NEVER-close text. Regression +tests in `dispatch.bats` verify all of this statically. -- 2.47.3 From f883f39dbf8b90ac8a4f5c7470d9cc4bd32eaf7e Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 15 May 2026 11:06:49 -0700 Subject: [PATCH 3/4] =?UTF-8?q?fix(#158):=20address=20NIT=20feedback=20?= =?UTF-8?q?=E2=80=94=20clarify=20enforcement=20split,=20clean=20=C2=A79=20?= =?UTF-8?q?prose?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev-loop-spec.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/dev-loop-spec.md b/docs/dev-loop-spec.md index 670f276..3c71812 100644 --- a/docs/dev-loop-spec.md +++ b/docs/dev-loop-spec.md @@ -274,7 +274,7 @@ Every worker template begins with an `⛔ ABSOLUTE CONSTRAINTS` section containi - **NEVER use the gitea-aweiker token.** All API calls use the gitea-rodin token only. - **NEVER act on a PR with active REQUEST_CHANGES.** Fix the findings first. -These constraints are statically enforced by `check-invariants.sh`: S1 and S9 cover the dispatch script (no merge, no close); S8 and S10 cover worker templates (no merge calls, no close calls, and NEVER-close text present in each). +The first two constraints are statically enforced by `check-invariants.sh`: S1 and S9 cover the dispatch script (no merge, no close); S8 and S10 cover worker templates (no merge calls, no close calls, and NEVER-close text present in each). The remaining two constraints (token usage and REQUEST_CHANGES gate) are enforced by runtime logic. --- @@ -296,5 +296,4 @@ script never had a close call, but workers could reason their way into calling `PATCH /pulls/{id}` with `state=closed`. All worker templates now include `NEVER close a PR` in their ABSOLUTE CONSTRAINTS section. Invariant S9 verifies the dispatch script contains no close calls. Invariant S10 verifies -worker templates contain no close calls and each contains the NEVER-close text. Regression -tests in `dispatch.bats` verify all of this statically. +worker templates contain no close calls and each contains the NEVER-close text. Regression tests in `dispatch.bats` statically verify all of these constraints. -- 2.47.3 From ec6fdbff4290a7fbf9fc7277aebabc4e7d5dc02d Mon Sep 17 00:00:00 2001 From: Rodin Date: Fri, 15 May 2026 15:40:53 -0700 Subject: [PATCH 4/4] =?UTF-8?q?fix(#158):=20address=20bot=20feedback=20?= =?UTF-8?q?=E2=80=94=20correct=20S8/S10=20description,=20fix=20=C2=A79=20p?= =?UTF-8?q?rose=20break?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dev-loop-spec.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/dev-loop-spec.md b/docs/dev-loop-spec.md index 3c71812..48283f9 100644 --- a/docs/dev-loop-spec.md +++ b/docs/dev-loop-spec.md @@ -274,7 +274,7 @@ Every worker template begins with an `⛔ ABSOLUTE CONSTRAINTS` section containi - **NEVER use the gitea-aweiker token.** All API calls use the gitea-rodin token only. - **NEVER act on a PR with active REQUEST_CHANGES.** Fix the findings first. -The first two constraints are statically enforced by `check-invariants.sh`: S1 and S9 cover the dispatch script (no merge, no close); S8 and S10 cover worker templates (no merge calls, no close calls, and NEVER-close text present in each). The remaining two constraints (token usage and REQUEST_CHANGES gate) are enforced by runtime logic. +The first two constraints are statically enforced by `check-invariants.sh`: S1 and S9 cover the dispatch script (no merge, no close); S8 covers worker templates (no merge calls); S10 covers worker templates (no close calls, with NEVER-close text verified present in each). The remaining two constraints (token usage and REQUEST_CHANGES gate) are enforced by runtime logic. --- @@ -296,4 +296,6 @@ script never had a close call, but workers could reason their way into calling `PATCH /pulls/{id}` with `state=closed`. All worker templates now include `NEVER close a PR` in their ABSOLUTE CONSTRAINTS section. Invariant S9 verifies the dispatch script contains no close calls. Invariant S10 verifies -worker templates contain no close calls and each contains the NEVER-close text. Regression tests in `dispatch.bats` statically verify all of these constraints. +worker templates contain no close calls and each contains the NEVER-close text. + +Regression tests in `dispatch.bats` statically verify all of these constraints. -- 2.47.3