Commit graph

58 commits

Author SHA1 Message Date
openhands
a66bd91721 fix: Replace Codeberg dependency with local Forgejo instance (#611)
- Add setup_forge() to bin/disinto: provisions Forgejo via Docker,
  creates admin + bot users (dev-bot, review-bot), generates API
  tokens, creates repo, and pushes code — all automated
- Rename env vars: CODEBERG_TOKEN→FORGE_TOKEN, REVIEW_BOT_TOKEN→
  FORGE_REVIEW_TOKEN, CODEBERG_REPO→FORGE_REPO, CODEBERG_API→
  FORGE_API, CODEBERG_WEB→FORGE_WEB, CODEBERG_BOT_USERNAMES→
  FORGE_BOT_USERNAMES (with backwards-compat fallbacks)
- Rename API helpers: codeberg_api()→forge_api(), codeberg_api_all()
  →forge_api_all() (with compat aliases)
- Add forge_url field to project TOML; load-project.sh derives
  FORGE_API/FORGE_WEB from forge_url + repo
- Update parse_repo_slug() to accept any host URL, not just codeberg
- Forgejo data stored under ~/.disinto/forgejo/ (not in factory repo)
- Update all 58 files: agent scripts, formulas, docs, site HTML

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 16:57:12 +00:00
openhands
604d1f13ca fix: feat: dev-poll checks priority-labeled issues before plain backlog (#555)
Add two-tier backlog pickup in dev-poll.sh:
1. in-progress issues (existing)
2. priority + backlog issues (FIFO within tier)
3. plain backlog issues (FIFO within tier)

The priority label coexists with backlog (not a replacement).
ensure_priority_label() auto-creates the label if missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:41:57 +00:00
openhands
7f2c5efd9d fix: fix: dev-poll pre-lock should merge chore/gardener PRs without issue numbers (#539)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 09:12:04 +00:00
openhands
00b20b5a67 fix: break duplicate-detection false positive in pre-lock section
Add log statement between pre-lock merge exit and lock check to break
a coincidental 5-line sliding-window match with dev-agent.sh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 06:52:39 +00:00
openhands
236e19eae1 fix: dev-poll should attempt direct merges before checking agent lock (#531)
Move the direct-merge scan (approved + CI green → try_direct_merge())
above the lock check. Merging an approved PR is a single API call that
doesn't need the dev-agent lock or a Claude session. This ensures
approved PRs get merged even while a dev-agent is running on an
unrelated issue.

The lock still guards dev-agent spawning (AD-002 preserved). Direct
merge failures fall through to the post-lock code for dev-agent
fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 06:46:26 +00:00
openhands
962f26b24d fix: Stale ${PROJECT_NAME:-harb} fallbacks in agent scripts (#400)
Replace all harb-specific fallbacks with generic 'default' sentinel
in dev-agent.sh, dev-poll.sh, action-agent.sh, and action-poll.sh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:25:13 +00:00
openhands
85fffd9fb7 fix: CI fix counter can be wasted by guard hits — consider check_only mode (#377)
Orphan and stuck-PR CI-failure paths in dev-poll.sh called
handle_ci_exhaustion without check_only, incrementing the fix counter on
every poll cycle even when guards (session checks, is_blocked) prevented
an actual agent launch. This could exhaust the 3-attempt budget without
any real fix attempts.

Now both paths use the same two-phase pattern as the backlog scan:
1. check_only during the scan (no counter increment)
2. Increment atomically at actual launch time

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:22:07 +00:00
openhands
d29c6ad1c9 fix: dev-poll.sh: redundant manual state exclusions alongside ci_passed (#113)
Add ci_failed() helper to lib/ci-helpers.sh and replace three compound
`! ci_passed && CI_STATE != "" && != "pending" && != "unknown"` patterns
in dev/dev-poll.sh with the cleaner ci_failed() call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 06:10:39 +00:00
openhands
bda9240268 refactor: extract ensure_blocked_label_id to lib/ci-helpers.sh (#352)
Move ensure_blocked_label_id() from dev/phase-handler.sh into
lib/ci-helpers.sh to eliminate the duplicate blocked-label creation
curl block that existed in both phase-handler.sh and dev-poll.sh.

Both dev-agent.sh and action-agent.sh now source lib/ci-helpers.sh
so the function is available when phase-handler.sh calls it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 05:06:12 +00:00
openhands
61c44d31b1 fix: refactor: replace escalation JSONL with blocked label + diagnostic comment (#352)
Replace the unreliable escalation JSONL system (supervisor/escalations-*.jsonl
consumed by gardener) with direct blocked label + diagnostic comment on the
original issue.

When a dev-agent or action-agent session fails (PHASE:failed, idle timeout,
crash, CI exhausted):
- Capture last 50 lines from tmux pane via tmux capture-pane
- Post a structured diagnostic comment on the issue (exit reason, timestamp,
  PR number, tmux output)
- Label the issue "blocked" (instead of restoring "backlog")
- Remove in-progress label

Removed:
- Escalation JSONL write paths in dev-agent.sh, phase-handler.sh, dev-poll.sh,
  action-agent.sh
- is_escalated() helper in dev-poll.sh
- Escalation triage (P2f section) in supervisor-poll.sh
- Escalation processing + recipe engine in gardener-poll.sh
- ci-escalation-recipes step from run-gardener.toml formula
- escalations*.jsonl from .gitignore

Added:
- post_blocked_diagnostic() shared helper in phase-handler.sh
- ensure_blocked_label_id() helper (creates label via API if not exists)
- is_blocked() helper in dev-poll.sh (replaces is_escalated)
- Blocked issues listing in supervisor/preflight.sh

Kept:
- Matrix notifications on failure (unchanged)
- CI fix counter logic (still tracks attempts)
- needs_human injection in supervisor/gardener (not escalation-related)
- Gardener grooming (gardener-agent.sh still invoked)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 04:18:43 +00:00
openhands
e5965e71d4 fix: Stale REQUEST_CHANGES reviews still trigger re-work (#336)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 00:05:09 +00:00
openhands
f78fbc1da6 fix: bundled dust cleanup — lib/matrix_listener.sh (#264)
- Remove dead ROOM_ENCODED and EVENT_ID variables from matrix_listener.sh
  (were suppressed with SC2034 instead of removed)
- Remove dead REPO variable from dev-poll.sh and review-poll.sh
- Update header comment in matrix_listener.sh to list all 5 reply-routing
  cases (supervisor, gardener, dev, review, vault, action)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:40:31 +00:00
openhands
3a1df8f233 fix: dev-poll.sh has no explicit guard for action-labeled issues (#233)
Add skip guards for `action`, `prediction/backlog`, and `prediction/unreviewed`
labels in both the orphan scan and backlog scan, matching the existing `formula`
guard pattern. Issues with these labels will no longer be picked up by dev-agent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:15:03 +00:00
openhands
1d797c0303 fix: address review — guard before CI counter, cover all spawn points
- Move tmux session guard BEFORE handle_ci_exhaustion in both CI-fix
  paths so poll cycles with an active session don't waste fix attempts
- Add tmux guards to recovery spawn (orphan, no PR) and both
  agent-merge fallback paths (orphan + stuck-PR)
- Use continue instead of exit 0 when guard fires in stuck-PR loop
  so remaining PRs are still checked

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 11:45:19 +00:00
openhands
4feb1fba97 fix: dev-poll spawns duplicate agents — no tmux session guard (#371)
Add tmux has-session check before spawning dev-agent.sh at all four
spawn points (orphan REQUEST_CHANGES, orphan CI fix, stuck-PR
REQUEST_CHANGES, stuck-PR CI fix). If a tmux session already exists
for the issue, log and skip instead of spawning a duplicate agent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 11:45:19 +00:00
openhands
a58aef90d3 fix: too_large branch still uses string label '"underspecified"' (#213)
Look up UNDERSPECIFIED_LABEL_ID via the Gitea labels API (with fallback)
and use the numeric ID in both phase-handler.sh (PHASE:failed/too_large)
and dev-poll.sh (preflight too_large), matching the pattern already used
for BACKLOG_LABEL_ID.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 09:50:20 +00:00
openhands
6f30614dda fix: fix: guard blocks merge injection — Claude closes issue without merging (#344)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 07:37:32 +00:00
johba
b78b22d830 fix: fix: dev-poll backlog selection is LIFO — should be FIFO (#349) (#350)
Fixes #349

## Changes
Add &sort=oldest to the backlog API call in dev/dev-poll.sh (line 401) so issues are picked FIFO instead of the Gitea default LIFO order.

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/350
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-20 08:33:03 +01:00
openhands
70aea63521 fix: Dual curl calls for HAS_APPROVE / HAS_CHANGES create a race window (#321)
Each of the three review-check sites (orphan, stuck-PR, backlog) now
fetches reviews with a single curl call, storing the JSON response and
jq-filtering both HAS_APPROVE and HAS_CHANGES from the cached result.
This eliminates the race window where a review submitted between the
two calls could cause a transient mismatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:59:51 +00:00
openhands
08d702b055 fix: fix: stale REQUEST_CHANGES reviews are invisible to dev-poll stuck-PR check (#319)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:24:48 +00:00
openhands
1ab700c87a fix: feat: review + dev-poll skip CI gate for non-code PRs (#266)
Add diff_has_code_files() and ci_required_for_pr() helpers to
ci-helpers.sh. Non-code PRs (docs/*, formulas/*, evidence/*, *.md)
that have no CI results now skip the CI gate instead of being stuck
forever.

Applied to:
- review-pr.sh: CI gate skipped for non-code PRs
- review-poll.sh: CI gate skipped for non-code PRs
- dev-poll.sh: CI state treated as "success" for non-code PRs in
  orphan, stuck-PR, and backlog merge paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:48:00 +00:00
openhands
d1cea6c0bb fix: apply same REQUEST_CHANGES/CI-pending fix to PRIORITY 1 block 2026-03-18 21:03:53 +00:00
openhands
34ddbef3fd fix: PRIORITY 1.5 misses REQUEST_CHANGES when CI is not yet settled (#41) 2026-03-18 20:50:56 +00:00
openhands
f73d5f471e fix: feat: dev-agent merges its own PRs via non-admin Codeberg account (#172)
- phase-handler.sh: remove do_merge(); on APPROVAL inject exact API
  commands for agent to merge+close directly; PHASE:done now only
  does local cleanup (tmux, worktree, labels) — merge already done
- dev-agent.sh: update PHASE_PROTOCOL_INSTRUCTIONS — Approved means
  merge via API, close issue, then write PHASE:done
- dev-poll.sh: remove try_merge_or_rebase(); for approved+CI-green
  orphaned PRs, spawn dev-agent (recovery mode) to merge instead
- .env.example: document new token roles (CODEBERG_TOKEN = bot for
  push/PR/merge; REVIEW_BOT_TOKEN = human account for approvals)
- AGENTS.md: update token descriptions to match new roles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 17:59:36 +00:00
openhands
d904192ab7 fix: Escalation write-once guard is not atomic (pre-existing) (#154)
- `ci_fix_check_and_increment` now accepts an optional `check_only` arg:
  - count < 3, check_only: returns `ok:N` without incrementing (deferred
    to launch time, preserving the WAITING_PRS protection)
  - count < 3, non-check_only: increments and returns `ok:N` (unchanged)
  - count == 3 (any mode): atomically bumps to 4 and returns
    `exhausted_first_time:3` — only one concurrent poller can win this
  - count > 3 (any mode): returns `exhausted:N` with no write

- `handle_ci_exhaustion` unified to a single code path for both
  check_only and non-check_only:
  - Writes escalation JSONL + matrix_send only when sentinel is
    `exhausted_first_time` — never on a bare integer comparison outside
    a lock
  - Removes the two separate `ci_fix_increment` bump-to-4 calls that
    were racy (the sentinel bump is now inside the flock in Python)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 11:44:30 +00:00
openhands
4dc64ea65b fix: restore deferred increment for backlog path to prevent counter leak
The previous commit introduced a counter leak in the backlog scan path:
handle_ci_exhaustion (without check_only) atomically incremented the CI
fix counter before the WAITING_PRS guard, so an exit 0 that never spawned
a dev-agent would silently consume one of the three allowed fix attempts.

Restore the READY_PR_FOR_INCREMENT / deferred-increment mechanism:
- Backlog scan calls handle_ci_exhaustion with "check_only" (read-only,
  no increment) to detect exhaustion without touching the counter.
- The counter is bumped atomically at LAUNCH time via handle_ci_exhaustion
  (without check_only), so the increment only happens when we are certain
  a dev-agent is being spawned. If a concurrent poller already exhausted
  the counter between scan and launch, the LAUNCH call returns 0 and we
  bail out cleanly without double-spawning.

The in-progress, stuck-PR, and try_merge_or_rebase paths are unaffected:
they call handle_ci_exhaustion without check_only, which continues to use
the atomic ci_fix_check_and_increment to prevent concurrent double-spawning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 10:34:41 +00:00
openhands
7bf13567fd fix: TOCTOU in handle_ci_exhaustion: check-then-act not atomic (#125)
Add ci_fix_check_and_increment() that performs read + threshold-check +
conditional increment in a single flock-protected Python call, replacing
the prior three-step sequence (ci_fix_count / bash check / ci_fix_increment)
that allowed two concurrent poll invocations to both pass the threshold and
spawn duplicate dev-agents for the same PR.

handle_ci_exhaustion now calls ci_fix_check_and_increment atomically and
returns the new count in CI_FIX_ATTEMPTS; all separate ci_fix_increment
calls after handle_ci_exhaustion (including the deferred READY_PR_FOR_INCREMENT
mechanism) are removed. Log messages updated from CI_FIX_ATTEMPTS+1 to
CI_FIX_ATTEMPTS to reflect the post-increment count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 10:22:24 +00:00
openhands
7d51e5e333 fix: Add formula guard to backlog scan path (#127) 2026-03-18 09:49:44 +00:00
openhands
32ee53517f fix: In-progress formula issue causes infinite dev-agent respawn (#115)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 06:41:43 +00:00
openhands
1352620c3d fix: ci_fix_count/ci_fix_increment not atomic — potential race under concurrent polls (#118)
Wrap ci_fix_count(), ci_fix_increment(), and ci_fix_reset() with flock
on a shared lockfile to prevent concurrent modification of the JSON
tracker. Uses flock(1) in command-wrapping mode so each Python process
holds an exclusive lock for the duration of its read-modify-write cycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 06:30:17 +00:00
openhands
cf8446b451 fix: try_merge_or_rebase rebase-failure spawn bypasses ci_fix_increment (#56)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 04:05:18 +00:00
openhands
ff02b1e653 fix: Three near-identical CI-exhaustion blocks should be a shared function (#58)
Extract CI-exhaustion check/escalate logic into handle_ci_exhaustion() helper.
All three call sites (orphaned PRs, stuck PRs, backlog PRs) now use the shared
function, eliminating future drift between the copies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 03:21:27 +00:00
openhands
8e600787c1 fix: ci_passed() still lives in dev/dev-poll.sh, not lib/ (#70)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 02:05:54 +00:00
openhands
bd02330b22 fix: shellcheck TODO has no enforcement — || true may never be removed (#71)
- Fix SC2164: add || exit 1 to bare cd in update-prompt.sh
- Fix SC2155: separate declare and assign in env.sh, supervisor-poll.sh, dev-agent.sh
- Fix SC2034: inline suppression for vars used by sourced helpers
- Remove unused `mergeable` declaration, rename unused loop var to `_w`
- Remove || true from shellcheck CI step — failures are now blocking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 01:53:02 +00:00
openhands
df2522a7cb fix: address review findings from issue #67 escalation refactor
- supervisor: skip *.done.jsonl in escalation glob (bug: wildcard matched
  harb.done.jsonl producing spurious 'pending' log noise every cycle)
- supervisor: use wc -l instead of grep -c . for line counting (style nit)
- supervisor: consume gardener-esc-resolved.log via fixed() so escalation
  resolutions appear in end-of-cycle supervisor reporting
- dev-poll: update all 'escalated to supervisor' log/matrix strings to
  'escalated to gardener' (lines 263, 268, 344, 420)
- gardener: track _esc_total_created across all escalation entries and
  write count to supervisor/gardener-esc-resolved.log after processing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 18:30:57 +00:00
openhands
150ede5605 fix: refactor: move escalation processing from supervisor to gardener (#67)
- dev-poll.sh: write escalations to per-project files
  (supervisor/escalations-{PROJECT_NAME}.jsonl) and add "project" field
  so each project's escalations are isolated; update is_escalated() to
  read from the same per-project paths
- gardener-poll.sh: add escalation processing block that reads the
  per-project escalation file, fetches CI logs via Woodpecker, and
  creates per-file ShellCheck sub-issues or generic CI failure issues
  labeled backlog — runs with the correct CODEBERG_API and
  WOODPECKER_REPO_ID already loaded from the project TOML
- supervisor-poll.sh: remove the escalation processing block; replace
  with a simple flog report counting pending escalations per project

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 17:32:56 +00:00
openhands
13bc948b1d fix: address review findings for escalation race condition, SQL injection, and sc_codes scope
- Race condition: mv escalations.jsonl to a PID-stamped snapshot before
  processing so concurrent dev-poll appends go to a fresh file; rm snapshot
  after loop — no entries are ever silently dropped
- SQL injection: validate ESC_PR_SHA is a 40-char hex string before
  interpolating into the wpdb query
- sc_codes scope: compute per-file from file_errors (already filtered to
  that file) instead of the entire step log; also switch grep to -F so
  dots in filenames are not treated as regex wildcards
- step_pid validation: reject non-integer values from Woodpecker API before
  passing as CLI argument
- Fallback body now distinguishes "CI logs unavailable" from "logs found
  but issue creation API calls failed"
- ESC_GENERIC_FAIL: avoid leading blank line by using conditional separator
  and fix code-block opening newline
- is_escalated(): remove dead esc_file/done_file locals; add Python-level
  int() guard so empty/non-numeric issue or pr values fail cleanly instead
  of producing a syntax error suppressed by 2>/dev/null

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 15:11:53 +00:00
openhands
d9520f48a6 fix: feat: supervisor breaks down escalated CI failures into sub-issues (#52)
- supervisor-poll.sh: replace P3 escalation log with actionable sub-issue creation.
  For each entry in escalations.jsonl: fetch CI logs via woodpecker-cli, create one
  sub-issue per file for ShellCheck failures, one combined issue for other CI failures,
  or a fallback investigation issue if logs are unavailable. Move processed entries to
  escalations.done.jsonl and clear escalations.jsonl.
- dev-poll.sh: add is_escalated() helper that checks both escalations.jsonl and
  escalations.done.jsonl; use it (alongside ci_fix_count >= 3) in all three CI-fix
  spawn paths so escalated PRs are skipped even if the ci-fixes tracker is reset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 14:32:41 +00:00
johba
531ae5cf71 fix: escalate once then continue to backlog (#59)
Two bugs after #53 merged:
1. Escalation written every poll cycle (4 entries in 30min) — now writes once, bumps counter to 4 to skip
2. Exit after escalation blocked backlog work — now falls through to pick up next issue

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/59
Reviewed-by: review_bot <review_bot@noreply.codeberg.org>
2026-03-17 15:14:48 +01:00
johba
c24adc4ea2 fix: limit CI fix respawn to 3 attempts, then escalate to supervisor (#53)
Dev-poll spawned a fresh agent every 10min for CI failures. Each agent started with CI_FIX_COUNT=0 — infinite loop.

Now tracks attempts per PR in `/tmp/dev-poll-ci-fixes-{project}.json`. After 3 failed rounds:
- Writes escalation to `supervisor/escalations.jsonl`
- Sends Matrix alert
- Stops respawning

Part of #52 (supervisor escalation pipeline).

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/53
Reviewed-by: review_bot <review_bot@noreply.codeberg.org>
2026-03-17 13:15:49 +01:00
openhands
ef77c56217 fix: extract ci_passed() helper — fix all CI gates for no-CI projects
dev-poll.sh had 5 places checking CI_STATE='success', all blocking
projects without CI. Extracted ci_passed() helper that treats
empty/pending/unknown as pass when WOODPECKER_REPO_ID=0.
2026-03-17 09:51:18 +00:00
openhands
1b3559bba7 fix: enforce single-threaded pipeline per project
Don't start new issues while open PRs are waiting for review/CI.
This prevents dev-agent from churning through backlog issues
without reviews landing first.
2026-03-17 09:17:02 +00:00
openhands
249eef86c1 fix: per-project lock and log files for dev-poll
Hardcoded /tmp/dev-agent.lock meant harb and disinto dev-polls shared
a lock — one project's running agent blocked the other. Now uses
/tmp/dev-agent-{project}.lock and dev-agent-{project}.log.
2026-03-17 08:18:24 +00:00
johba
9050413994 refactor: split supervisor into infra + per-project, make poll scripts config-driven
Supervisor split (#26):
- Layer 1 (infra): P0 memory, P1 disk, P4 housekeeping — runs once, project-agnostic
- Layer 2 (per-project): P2 CI/dev-agent, P3 PRs/deps — iterates projects/*.toml
- Adding a new project requires only a new TOML file, no code changes

Poll scripts accept project TOML arg (#27):
- dev-poll.sh, review-poll.sh, gardener-poll.sh accept optional project TOML as $1
- env.sh loads PROJECT_TOML if set, overriding .env defaults
- Cron: `dev-poll.sh projects/versi.toml` targets that project

New files:
- lib/load-project.sh: TOML to env var loader (Python tomllib)
- projects/versi.toml: current project config extracted from .env

Backwards compatible: scripts without a TOML arg fall back to .env config.

Closes #26, Closes #27

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:57:18 +01:00
johba
98f0c40106 refactor: rewrite parse-deps.py as pure bash, remove only Python from repo
Replace lib/parse-deps.py with lib/parse-deps.sh to keep the toolchain
all-bash. Rewrite supervisor P3b cycle detection and P3c stale dep check
as pure bash using associative arrays and DFS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:22:53 +01:00
johba
6cf580c010 refactor: extract shared dep parser to lib/parse-deps.py (Closes #20)
Single source of truth for dependency parsing, replacing three copies:
- dev-poll.sh get_deps() now calls parse-deps.py
- supervisor P3b/P3c import parse_deps() via importlib

Supports stdin, argument, and --json modes for different callers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:16:49 +01:00
johba
77cb4c4643 refactor: rename factory/ → supervisor/, factory-poll → supervisor-poll
The supervisor agent was confusingly named "factory" (same as the
project). Rename directory, script, log, lock, status, and escalation
files. Update all references across scripts and docs.

FACTORY_ROOT env var unchanged (refers to project root, not agent).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 18:06:25 +01:00
openhands
c5fdd8ac50 fix: always rebase on merge failure, don't trust mergeable field
Codeberg's mergeable field flickers between true/false — unreliable
for deciding whether to rebase. Just attempt rebase on any non-200/204.
Worst case it's a no-op. Also added git fetch before rebase.
2026-03-15 10:51:09 +00:00
openhands
c22f1acbdf fix: add matrix notifications for silent failure paths
dev-poll.sh:
- Merge conflicts (rebase attempt + outcome)
- Non-conflict merge failures (HTTP code)
- Low memory skip
- New issue launch

review-poll.sh:
- Review script failure
2026-03-15 10:27:23 +00:00
openhands
b4d14c4c98 fix: auto-rebase on merge conflict (mergeable=false)
When merge returns non-200, check mergeable flag. If false,
rebase the PR branch onto master via worktree. If rebase fails,
spawn dev-agent to resolve. Prevents infinite 405 retry loops.

Extracted try_merge_or_rebase() helper used at all 3 merge points.
2026-03-15 10:21:40 +00:00