From 39031de2e47d4fd1117ff717a5839e315b501c44 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 9 Apr 2026 13:46:29 +0000 Subject: [PATCH] chore: gardener housekeeping 2026-04-09 - Update AGENTS.md watermark to HEAD (31b55ff) - Update gardener/AGENTS.md watermark to HEAD - Close #419 (vision: all sprint sub-issues done) - Close #494 (resolved by #502+#503) - Close #477 (obsolete: #379 deployed, env.sh guard is correct) - Add AC + affected files to #471, #498, #499; promote to backlog Co-Authored-By: Claude Sonnet 4.6 --- AGENTS.md | 2 +- gardener/AGENTS.md | 2 +- gardener/pending-actions.json | 46 ++++++++++++++++++++++++++++------ gardener/pending-actions.jsonl | 9 +++++++ 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 gardener/pending-actions.jsonl diff --git a/AGENTS.md b/AGENTS.md index cacedf7..0c6cb1a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ - + # Disinto — Agent Instructions ## What this repo is diff --git a/gardener/AGENTS.md b/gardener/AGENTS.md index 394cac3..46181f1 100644 --- a/gardener/AGENTS.md +++ b/gardener/AGENTS.md @@ -1,4 +1,4 @@ - + # Gardener Agent **Role**: Backlog grooming — detect duplicate issues, missing acceptance diff --git a/gardener/pending-actions.json b/gardener/pending-actions.json index 656000e..3852ac2 100644 --- a/gardener/pending-actions.json +++ b/gardener/pending-actions.json @@ -1,17 +1,47 @@ [ { - "action": "comment", - "issue": 446, - "body": "Closing as resolved: sub-issues #442, #443, #444, #445 are all closed. The gardener formula now includes an `agents-update` step that checks watermarks and keeps AGENTS.md files current. The last gardener run (commit faaaeb0) confirmed the step is working — all per-directory AGENTS.md files were updated." + "action": "close", + "issue": 419, + "reason": "All sprint sub-issues #437\u2013#454 are closed and merged. The blast-radius approval tiers vision goal is complete." }, { "action": "close", - "issue": 446, - "reason": "resolved: sub-issues fixed and gardener agents-update step is operational" + "issue": 494, + "reason": "Resolved by merged sub-issues: #502 (load-project.sh derives container repo paths) and #503 (entrypoint.sh workaround removed). Both PRs merged." }, { - "action": "remove_label", - "issue": 419, - "label": "blocked" + "action": "close", + "issue": 477, + "reason": "Obsolete: issue assumed #379 (while-true loop) was not yet deployed, but #379 was merged and closed on 2026-04-08. The DISINTO_CONTAINER guard in lib/env.sh is now correct \u2014 compose env vars flow through the while-true loop process tree, so .env should NOT be sourced inside containers." + }, + { + "action": "edit_body", + "issue": 498, + "body": "## Problem\n\n`has_responses_to_process` is only set to `true` inside the `open_arch_prs >= 3` gate in `architect/architect-run.sh` (line 521). When fewer than 3 architect PRs are open, ACCEPT/REJECT responses on existing PRs are never processed \u2014 the response-processing block at line 688 defaults to `false` and is skipped entirely.\n\nThis means that if a user ACCEPTs or REJECTs a pitch while the open PR count is below 3, the architect agent will never handle the response.\n\n## Fix\n\nMove the ACCEPT/REJECT response scan outside the `open_arch_prs >= 3` gate. Set `has_responses_to_process=true` unconditionally whenever any open architect PRs have ACCEPT/REJECT comments \u2014 not only when the 3-PR cap is hit.\n\n## Affected files\n\n- `architect/architect-run.sh` (lines 521\u2013541: the `>= 3` PR gate and response scan block; line 688: the response-processing block)\n\n## Acceptance criteria\n\n- [ ] ACCEPT/REJECT comments on architect PRs are processed regardless of how many PRs are open\n- [ ] The `>= 3` early-exit guard still works for the \"no responses, too many PRs\" case (skip pitching)\n- [ ] A test with 1 open architect PR that has an ACCEPT comment results in the architect processing it\n- [ ] Existing architect formula step ordering is preserved\n\n---\n*Flagged by AI reviewer in PR #496*" + }, + { + "action": "add_label", + "issue": 498, + "label": "backlog" + }, + { + "action": "edit_body", + "issue": 499, + "body": "## Problem\n\nIn `architect/architect-run.sh` line 203, the `has_open_subissues` function compares `.number` (a JSON integer) against `$vid` (a bash string via `--arg`). In jq, `42 != \"42\"` evaluates to `true` (different types are never equal), so the self-exclusion filter never fires. The self-exclusion logic is silently broken \u2014 though low-risk in practice since vision issues don't contain 'Decomposed from #N' in their own bodies.\n\n## Fix\n\nCast the string to a number in jq:\n\n```jq\nselect(.number != ($vid | tonumber))\n```\n\n## Affected files\n\n- `architect/architect-run.sh` (line 203: `select(.number != $vid)` in the `has_open_subissues` function)\n\n## Acceptance criteria\n\n- [ ] `select(.number != ($vid | tonumber))` replaces `select(.number != $vid)` at line 203\n- [ ] ShellCheck passes (the jq expression is in a heredoc/string, not inline shell)\n- [ ] `has_open_subissues` correctly excludes the vision issue itself when checking for open sub-issues\n\n---\n*Flagged by AI reviewer in PR #496*" + }, + { + "action": "add_label", + "issue": 499, + "label": "backlog" + }, + { + "action": "edit_body", + "issue": 471, + "body": "## Bug description\n\nWhen dev-bot picks a backlog issue and launches dev-agent.sh, a second dev-poll instance (dev-qwen) can race ahead and mark the issue as stale/blocked before dev-agent.sh finishes claiming it.\n\n## Reproduction\n\nObserved on issues #443 and #445 (2026-04-08):\n\n**#443 timeline:**\n- `20:39:03` \u2014 dev-bot removes `backlog`, adds `in-progress` (via dev-poll backlog pickup)\n- `20:39:04` \u2014 dev-qwen removes `in-progress`, adds `blocked` with reason `no_assignee_no_open_pr_no_lock`\n- `20:40:11` \u2014 dev-bot pushes commit (dev-agent was actually working the whole time)\n- `20:44:02` \u2014 PR merged, issue closed\n\n**#445 timeline:**\n- `20:54:03` \u2014 dev-bot adds `in-progress`\n- `20:54:06` \u2014 dev-qwen marks `blocked` (3 seconds later)\n- `20:55:13` \u2014 dev-bot pushes commit\n- `21:09:03` \u2014 PR merged, issue closed\n\nIn both cases, the work completed successfully despite being labeled blocked.\n\n## Root cause\n\n`issue_claim()` in `lib/issue-lifecycle.sh` performs three sequential API calls:\n1. PATCH assignee\n2. POST in-progress label\n3. DELETE backlog label\n\nMeanwhile, dev-poll on another agent (dev-qwen) runs its orphan scan, sees the issue labeled `in-progress` but with no assignee set yet (assign PATCH hasn't landed or was read stale), no open PR, and no lock file. It concludes the issue is stale and relabels to `blocked`.\n\nThe race window is ~1-3 seconds between in-progress being set and the assignee being visible to other pollers.\n\n## Affected files\n\n- `lib/issue-lifecycle.sh` \u2014 `issue_claim()` function: reorder API calls to set assignee before adding in-progress label\n- `dev/dev-poll.sh` \u2014 orphan/stale detection: add grace period (e.g. skip issues whose in-progress label was added < 30s ago via label event timestamp)\n\n## Acceptance criteria\n\n- [ ] `issue_claim()` sets assignee before adding `in-progress` label, OR writes lock file before any label changes\n- [ ] Stale detection in dev-poll skips issues where in-progress was added less than 30 seconds ago\n- [ ] No spurious `blocked` labels appear on freshly claimed issues in integration test scenario\n- [ ] Existing `issue_claim()` behavior is preserved for the happy path (single dev-poll instance)" + }, + { + "action": "add_label", + "issue": 471, + "label": "backlog" } ] diff --git a/gardener/pending-actions.jsonl b/gardener/pending-actions.jsonl new file mode 100644 index 0000000..e9f1913 --- /dev/null +++ b/gardener/pending-actions.jsonl @@ -0,0 +1,9 @@ +{"action":"close","issue":419,"reason":"All sprint sub-issues #437–#454 are closed and merged. The blast-radius approval tiers vision goal is complete."} +{"action":"close","issue":494,"reason":"Resolved by merged sub-issues: #502 (load-project.sh derives container repo paths) and #503 (entrypoint.sh workaround removed). Both PRs merged."} +{"action":"close","issue":477,"reason":"Obsolete: issue assumed #379 (while-true loop) was not yet deployed, but #379 was merged and closed on 2026-04-08. The DISINTO_CONTAINER guard in lib/env.sh is now correct — compose env vars flow through the while-true loop process tree, so .env should NOT be sourced inside containers."} +{"action":"edit_body","issue":498,"body":"## Problem\n\n`has_responses_to_process` is only set to `true` inside the `open_arch_prs >= 3` gate in `architect/architect-run.sh` (line 521). When fewer than 3 architect PRs are open, ACCEPT/REJECT responses on existing PRs are never processed — the response-processing block at line 688 defaults to `false` and is skipped entirely.\n\nThis means that if a user ACCEPTs or REJECTs a pitch while the open PR count is below 3, the architect agent will never handle the response.\n\n## Fix\n\nMove the ACCEPT/REJECT response scan outside the `open_arch_prs >= 3` gate. Set `has_responses_to_process=true` unconditionally whenever any open architect PRs have ACCEPT/REJECT comments — not only when the 3-PR cap is hit.\n\n## Affected files\n\n- `architect/architect-run.sh` (lines 521–541: the `>= 3` PR gate and response scan block; line 688: the response-processing block)\n\n## Acceptance criteria\n\n- [ ] ACCEPT/REJECT comments on architect PRs are processed regardless of how many PRs are open\n- [ ] The `>= 3` early-exit guard still works for the \"no responses, too many PRs\" case (skip pitching)\n- [ ] A test with 1 open architect PR that has an ACCEPT comment results in the architect processing it\n- [ ] Existing architect formula step ordering is preserved\n\n---\n*Flagged by AI reviewer in PR #496*"} +{"action":"add_label","issue":498,"label":"backlog"} +{"action":"edit_body","issue":499,"body":"## Problem\n\nIn `architect/architect-run.sh` line 203, the `has_open_subissues` function compares `.number` (a JSON integer) against `$vid` (a bash string via `--arg`). In jq, `42 != \"42\"` evaluates to `true` (different types are never equal), so the self-exclusion filter never fires. The self-exclusion logic is silently broken — though low-risk in practice since vision issues don't contain 'Decomposed from #N' in their own bodies.\n\n## Fix\n\nCast the string to a number in jq:\n\n```jq\nselect(.number != ($vid | tonumber))\n```\n\n## Affected files\n\n- `architect/architect-run.sh` (line 203: `select(.number != $vid)` in the `has_open_subissues` function)\n\n## Acceptance criteria\n\n- [ ] `select(.number != ($vid | tonumber))` replaces `select(.number != $vid)` at line 203\n- [ ] ShellCheck passes (the jq expression is in a heredoc/string, not inline shell)\n- [ ] `has_open_subissues` correctly excludes the vision issue itself when checking for open sub-issues\n\n---\n*Flagged by AI reviewer in PR #496*"} +{"action":"add_label","issue":499,"label":"backlog"} +{"action":"edit_body","issue":471,"body":"## Bug description\n\nWhen dev-bot picks a backlog issue and launches dev-agent.sh, a second dev-poll instance (dev-qwen) can race ahead and mark the issue as stale/blocked before dev-agent.sh finishes claiming it.\n\n## Reproduction\n\nObserved on issues #443 and #445 (2026-04-08):\n\n**#443 timeline:**\n- `20:39:03` — dev-bot removes `backlog`, adds `in-progress` (via dev-poll backlog pickup)\n- `20:39:04` — dev-qwen removes `in-progress`, adds `blocked` with reason `no_assignee_no_open_pr_no_lock`\n- `20:40:11` — dev-bot pushes commit (dev-agent was actually working the whole time)\n- `20:44:02` — PR merged, issue closed\n\n**#445 timeline:**\n- `20:54:03` — dev-bot adds `in-progress`\n- `20:54:06` — dev-qwen marks `blocked` (3 seconds later)\n- `20:55:13` — dev-bot pushes commit\n- `21:09:03` — PR merged, issue closed\n\nIn both cases, the work completed successfully despite being labeled blocked.\n\n## Root cause\n\n`issue_claim()` in `lib/issue-lifecycle.sh` performs three sequential API calls:\n1. PATCH assignee\n2. POST in-progress label\n3. DELETE backlog label\n\nMeanwhile, dev-poll on another agent (dev-qwen) runs its orphan scan, sees the issue labeled `in-progress` but with no assignee set yet (assign PATCH hasn't landed or was read stale), no open PR, and no lock file. It concludes the issue is stale and relabels to `blocked`.\n\nThe race window is ~1-3 seconds between in-progress being set and the assignee being visible to other pollers.\n\n## Affected files\n\n- `lib/issue-lifecycle.sh` — `issue_claim()` function: reorder API calls to set assignee before adding in-progress label\n- `dev/dev-poll.sh` — orphan/stale detection: add grace period (e.g. skip issues whose in-progress label was added < 30s ago via label event timestamp)\n\n## Acceptance criteria\n\n- [ ] `issue_claim()` sets assignee before adding `in-progress` label, OR writes lock file before any label changes\n- [ ] Stale detection in dev-poll skips issues where in-progress was added less than 30 seconds ago\n- [ ] No spurious `blocked` labels appear on freshly claimed issues in integration test scenario\n- [ ] Existing `issue_claim()` behavior is preserved for the happy path (single dev-poll instance)"} +{"action":"add_label","issue":471,"label":"backlog"}