From 80f287d5cfaa6502e4281c8f0039b35d876cad99 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 1 Jul 2026 13:20:30 +0100 Subject: [PATCH 1/7] fix(orchestrator): recognise implementation-swarm via KG-driven auto-merge allowlist The auto-merge author gate hardcoded claude-code/root/adf-* as the only recognised fleet logins, so every PR opened by the implementation-swarm agent was rejected with "not a recognised agent; human-authored PRs require manual merge" on every reconcile tick. This left 11 PRs stuck across terraphim-agents, terraphim-clients, terraphim-config-persistence, and terraphim-core. Move the allowlist to a KG markdown concept (crates/terraphim_orchestrator/kg/recognised_agents.md, synonyms:: line) following this repo's existing KG-driven-config convention, loaded via the new agent_allowlist_kg module. Operators can extend the allowlist by editing that file (or the ADF_RECOGNISED_AGENTS_KG-pointed deployed copy) without a rebuild. pr_review.rs stays I/O-free per its module contract; only the new loader module touches the filesystem. Also fixes an unrelated pre-existing terraphim_workspace test failure on macOS: path_inside_root_is_accepted joined against the raw tempdir path instead of the manager's canonicalised root, so it failed under the /var -> /private/var symlink. --- .../kg/recognised_agents.md | 14 ++ .../src/agent_allowlist_kg.rs | 128 ++++++++++++++++++ .../src/auto_merge_impl.rs | 9 +- crates/terraphim_orchestrator/src/lib.rs | 1 + .../terraphim_orchestrator/src/pr_poller.rs | 6 +- .../terraphim_orchestrator/src/pr_review.rs | 86 ++++++++---- crates/terraphim_workspace/src/lib.rs | 6 +- 7 files changed, 218 insertions(+), 32 deletions(-) create mode 100644 crates/terraphim_orchestrator/kg/recognised_agents.md create mode 100644 crates/terraphim_orchestrator/src/agent_allowlist_kg.rs diff --git a/crates/terraphim_orchestrator/kg/recognised_agents.md b/crates/terraphim_orchestrator/kg/recognised_agents.md new file mode 100644 index 000000000..a9985f997 --- /dev/null +++ b/crates/terraphim_orchestrator/kg/recognised_agents.md @@ -0,0 +1,14 @@ +# Recognised Agent + +Fleet automation accounts authorised to open auto-merge-eligible PRs. A +Gitea PR author login matching one of these `synonyms::` entries (or +starting with the `adf-` prefix, enforced separately in code) satisfies the +`require_agent_author` auto-merge gate without a human re-reviewing PR +authorship. All other quality gates (confidence, P0/P1 counts, diff size, +acceptance criteria) still apply. + +To onboard a new fleet automation account, add its exact Gitea login to the +`synonyms::` line below and restart (or wait for) the orchestrator's next +allowlist reload — no code change or rebuild required. + +synonyms:: claude-code, root, implementation-swarm diff --git a/crates/terraphim_orchestrator/src/agent_allowlist_kg.rs b/crates/terraphim_orchestrator/src/agent_allowlist_kg.rs new file mode 100644 index 000000000..0be8eb364 --- /dev/null +++ b/crates/terraphim_orchestrator/src/agent_allowlist_kg.rs @@ -0,0 +1,128 @@ +//! Loads the `recognised_agent` KG concept +//! (`crates/terraphim_orchestrator/kg/recognised_agents.md`) into the set of +//! fleet automation logins consumed by [`crate::pr_review::author_is_agent`]. +//! +//! Follows the project-wide KG markdown convention (see root `CLAUDE.md` +//! "Extending Knowledge Graph"): a `synonyms::` line lists the recognised +//! terms — here, exact-match Gitea PR author logins. Operators extend the +//! allowlist by editing that line; no rebuild is required because the +//! deployed copy under `/opt/ai-dark-factory/kg/recognised_agents.md` (or +//! the path in `ADF_RECOGNISED_AGENTS_KG`) is re-read from disk, falling +//! back to the binary's embedded copy if the file is missing. +//! +//! Parsing is a pure function ([`parse_recognised_agents`]) so it is testable +//! without I/O; only [`load_recognised_agents`] touches the filesystem. + +use std::collections::BTreeSet; +use std::path::Path; + +/// The `recognised_agents.md` shipped in the repo, embedded at compile time +/// as the fallback used when no on-disk KG file is found. +const DEFAULT_KG_MARKDOWN: &str = include_str!("../kg/recognised_agents.md"); + +/// Env var pointing at an on-disk override of `recognised_agents.md` +/// (e.g. `/opt/ai-dark-factory/kg/recognised_agents.md` in production, so +/// operators can extend the allowlist without redeploying the orchestrator +/// binary). +const KG_PATH_ENV_VAR: &str = "ADF_RECOGNISED_AGENTS_KG"; + +/// Default on-disk path checked when `ADF_RECOGNISED_AGENTS_KG` is unset, +/// relative to the orchestrator's working directory. +const DEFAULT_KG_RELATIVE_PATH: &str = "kg/recognised_agents.md"; + +/// Parse a `synonyms::` line (case-insensitive key, comma-separated values) +/// out of KG markdown, returning the recognised logins verbatim (trimmed, +/// case-preserved — Gitea logins are case-sensitive). +/// +/// Multiple `synonyms::` lines are merged. Lines that don't match the +/// directive are ignored, matching the tolerant parsing style used +/// elsewhere for this KG format (see `kg_router.rs`). +pub fn parse_recognised_agents(markdown: &str) -> BTreeSet { + markdown + .lines() + .filter_map(|line| { + let trimmed = line.trim(); + let lower = trimmed.to_ascii_lowercase(); + lower + .starts_with("synonyms::") + .then(|| trimmed["synonyms::".len()..].to_string()) + }) + .flat_map(|rest| { + rest.split(',') + .map(|s| s.trim().to_string()) + .collect::>() + }) + .filter(|s| !s.is_empty()) + .collect() +} + +/// Load the recognised-agent allowlist from disk, falling back to the +/// embedded default when the file is absent or unreadable. +/// +/// Path resolution: `ADF_RECOGNISED_AGENTS_KG` env var if set, else +/// `kg/recognised_agents.md` relative to the current working directory. +pub fn load_recognised_agents() -> BTreeSet { + let path = + std::env::var(KG_PATH_ENV_VAR).unwrap_or_else(|_| DEFAULT_KG_RELATIVE_PATH.to_string()); + let markdown = std::fs::read_to_string(Path::new(&path)) + .unwrap_or_else(|_| DEFAULT_KG_MARKDOWN.to_string()); + parse_recognised_agents(&markdown) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_embedded_default() { + let logins = parse_recognised_agents(DEFAULT_KG_MARKDOWN); + assert!(logins.contains("claude-code")); + assert!(logins.contains("root")); + assert!(logins.contains("implementation-swarm")); + } + + #[test] + fn parses_multiple_synonyms_lines() { + let markdown = "# Concept\n\nsynonyms:: alpha, beta\nsynonyms:: gamma\n"; + let logins = parse_recognised_agents(markdown); + assert_eq!( + logins, + ["alpha", "beta", "gamma"] + .into_iter() + .map(String::from) + .collect::>() + ); + } + + #[test] + fn ignores_unrelated_lines_and_trims_whitespace() { + let markdown = "# Title\n\nSome prose.\n\nsynonyms:: claude-code , root \n"; + let logins = parse_recognised_agents(markdown); + assert_eq!( + logins, + ["claude-code", "root"] + .into_iter() + .map(String::from) + .collect::>() + ); + } + + #[test] + fn returns_empty_set_when_no_synonyms_line_present() { + assert!(parse_recognised_agents("# Title\n\nJust prose, no directive.\n").is_empty()); + } + + #[test] + fn load_falls_back_to_embedded_default_when_env_path_missing() { + // SAFETY: test-only env mutation, no concurrent readers of this var + // in this crate's test suite. + unsafe { + std::env::set_var(KG_PATH_ENV_VAR, "/nonexistent/path/recognised_agents.md"); + } + let logins = load_recognised_agents(); + assert!(logins.contains("implementation-swarm")); + unsafe { + std::env::remove_var(KG_PATH_ENV_VAR); + } + } +} diff --git a/crates/terraphim_orchestrator/src/auto_merge_impl.rs b/crates/terraphim_orchestrator/src/auto_merge_impl.rs index e702e4676..573961de8 100644 --- a/crates/terraphim_orchestrator/src/auto_merge_impl.rs +++ b/crates/terraphim_orchestrator/src/auto_merge_impl.rs @@ -10,8 +10,8 @@ use crate::dispatcher::DispatchTask; #[cfg(feature = "quickwit")] use crate::quickwit; use crate::{ - config, dispatcher, post_merge_gate, pr_gate, pr_poller, pr_review, truncate_for_issue, - AgentOrchestrator, OrchestratorError, + agent_allowlist_kg, config, dispatcher, post_merge_gate, pr_gate, pr_poller, pr_review, + truncate_for_issue, AgentOrchestrator, OrchestratorError, }; impl AgentOrchestrator { @@ -58,7 +58,10 @@ impl AgentOrchestrator { return Ok(()); } - let criteria = pr_review::AutoMergeCriteria::default(); + let criteria = pr_review::AutoMergeCriteria { + recognised_agent_logins: agent_allowlist_kg::load_recognised_agents(), + ..pr_review::AutoMergeCriteria::default() + }; for (project_id, gitea_cfg) in targets { let tracker_cfg = terraphim_tracker::GiteaConfig { diff --git a/crates/terraphim_orchestrator/src/lib.rs b/crates/terraphim_orchestrator/src/lib.rs index 617cbba08..f94ea02ae 100644 --- a/crates/terraphim_orchestrator/src/lib.rs +++ b/crates/terraphim_orchestrator/src/lib.rs @@ -29,6 +29,7 @@ //! ``` pub mod adf_commands; +pub mod agent_allowlist_kg; pub mod agent_registry; pub mod agent_run_command; pub mod agent_run_record; diff --git a/crates/terraphim_orchestrator/src/pr_poller.rs b/crates/terraphim_orchestrator/src/pr_poller.rs index 3ce7b74d6..5ae575325 100644 --- a/crates/terraphim_orchestrator/src/pr_poller.rs +++ b/crates/terraphim_orchestrator/src/pr_poller.rs @@ -320,9 +320,11 @@ pub fn evaluate_pr_gates( project_id: &str, criteria: &AutoMergeCriteria, ) -> EvaluationOutcome { - if criteria.require_agent_author && !author_is_agent(&pr.author_login) { + if criteria.require_agent_author + && !author_is_agent(&pr.author_login, &criteria.recognised_agent_logins) + { return EvaluationOutcome::HumanReviewNeeded { - reason: agent_author_rejection_reason(&pr.author_login), + reason: agent_author_rejection_reason(&pr.author_login, &criteria.recognised_agent_logins), }; } if pr.diff_loc > criteria.max_diff_loc { diff --git a/crates/terraphim_orchestrator/src/pr_review.rs b/crates/terraphim_orchestrator/src/pr_review.rs index 13d2c3721..63aa39b39 100644 --- a/crates/terraphim_orchestrator/src/pr_review.rs +++ b/crates/terraphim_orchestrator/src/pr_review.rs @@ -57,6 +57,17 @@ pub struct AutoMergeCriteria { pub require_all_criteria: bool, pub max_diff_loc: u32, pub require_agent_author: bool, + /// Exact-match logins recognised as fleet automation accounts, in + /// addition to the `adf-` prefix rule applied by [`author_is_agent`]. + /// + /// Populated from the `recognised_agent` KG concept + /// (`crates/terraphim_orchestrator/kg/recognised_agents.md`) by + /// [`crate::agent_allowlist_kg::load_recognised_agents`] at orchestrator + /// startup; operators extend the allowlist by editing that markdown + /// file's `synonyms::` line, no rebuild required. The hardcoded default + /// here is a pure, I/O-free fallback so this module and its tests never + /// touch the filesystem. + pub recognised_agent_logins: std::collections::BTreeSet, } impl Default for AutoMergeCriteria { @@ -68,6 +79,10 @@ impl Default for AutoMergeCriteria { require_all_criteria: true, max_diff_loc: 500, require_agent_author: true, + recognised_agent_logins: ["claude-code", "root", "implementation-swarm"] + .into_iter() + .map(String::from) + .collect(), } } } @@ -155,7 +170,7 @@ pub fn parse_verdict(body: &str, comment_id: u64) -> Result String { +/// when it appears (verbatim) in `recognised_logins`, or starts with the +/// `adf-` fleet prefix. To allowlist a new automation account, add its login +/// to the `synonyms::` line in +/// `crates/terraphim_orchestrator/kg/recognised_agents.md` — no rebuild +/// required, the orchestrator re-reads it via +/// [`crate::agent_allowlist_kg::load_recognised_agents`]. +pub fn agent_author_rejection_reason( + login: &str, + recognised_logins: &std::collections::BTreeSet, +) -> String { + let known = recognised_logins + .iter() + .map(String::as_str) + .collect::>() + .join(", "); format!( "author `{login}` is not a recognised agent; human-authored PRs require manual merge. \ - To allowlist, add the login to the orchestrator fleet config \ - (`[[agents]]` in `orchestrator.toml`); recognised logins are exactly \ - `claude-code`, `root`, or any `adf-` prefix." + To allowlist, add the login to the `synonyms::` line in \ + `crates/terraphim_orchestrator/kg/recognised_agents.md`; recognised logins are \ + currently [{known}] or any `adf-` prefix." ) } /// Return `true` when `login` belongs to an automation account authorised to /// open auto-merge-eligible PRs. /// -/// Policy: the login exactly matches `claude-code` or `root`, or starts with -/// `adf-` (the ADF fleet agent prefix). Anything else — including human -/// maintainers, bots from other tenants, and Renovate/Dependabot — is -/// considered non-agent for auto-merge purposes. -pub fn author_is_agent(login: &str) -> bool { - matches!(login, "claude-code" | "root") || login.starts_with("adf-") +/// Policy: the login exactly matches an entry in `recognised_logins` (KG- +/// driven allowlist, see [`crate::agent_allowlist_kg`]), or starts with +/// `adf-` (the ADF fleet agent prefix, a structural convention rather than a +/// KG concept). Anything else — including human maintainers, bots from other +/// tenants, and Renovate/Dependabot — is considered non-agent for auto-merge +/// purposes. +pub fn author_is_agent(login: &str, recognised_logins: &std::collections::BTreeSet) -> bool { + recognised_logins.contains(login) || login.starts_with("adf-") } /// Strip HTML attributes from `

` tags so that formatting variations @@ -368,18 +399,21 @@ mod tests { #[test] fn author_is_agent_policy() { - assert!(author_is_agent("claude-code")); - assert!(author_is_agent("root")); - assert!(author_is_agent("adf-fleet")); - assert!(author_is_agent("adf-reviewer")); - assert!(!author_is_agent("alex")); - assert!(!author_is_agent("dependabot[bot]")); - assert!(!author_is_agent("renovate[bot]")); + let recognised = AutoMergeCriteria::default().recognised_agent_logins; + assert!(author_is_agent("claude-code", &recognised)); + assert!(author_is_agent("root", &recognised)); + assert!(author_is_agent("implementation-swarm", &recognised)); + assert!(author_is_agent("adf-fleet", &recognised)); + assert!(author_is_agent("adf-reviewer", &recognised)); + assert!(!author_is_agent("alex", &recognised)); + assert!(!author_is_agent("dependabot[bot]", &recognised)); + assert!(!author_is_agent("renovate[bot]", &recognised)); } #[test] fn agent_author_rejection_reason_includes_login_and_allowlist_hint() { - let reason = agent_author_rejection_reason("dependabot[bot]"); + let recognised = AutoMergeCriteria::default().recognised_agent_logins; + let reason = agent_author_rejection_reason("dependabot[bot]", &recognised); // AC: the rejection message contains the exact author login. assert!( reason.contains("author `dependabot[bot]`"), @@ -391,8 +425,8 @@ mod tests { "reason must mention allowlisting, got: {reason}" ); assert!( - reason.contains("orchestrator.toml"), - "reason must point to the fleet config file, got: {reason}" + reason.contains("kg/recognised_agents.md"), + "reason must point to the KG allowlist file, got: {reason}" ); // Hint must mirror the real author_is_agent() policy so operators are // not misled about which logins are already accepted. @@ -429,7 +463,7 @@ mod tests { }; assert!(reason.contains("renovate[bot]")); assert!(reason.contains("allowlist")); - assert!(reason.contains("orchestrator.toml")); + assert!(reason.contains("kg/recognised_agents.md")); } #[test] diff --git a/crates/terraphim_workspace/src/lib.rs b/crates/terraphim_workspace/src/lib.rs index 8acd7758e..5f5c147d0 100644 --- a/crates/terraphim_workspace/src/lib.rs +++ b/crates/terraphim_workspace/src/lib.rs @@ -676,7 +676,11 @@ mod tests { }; let mgr = WorkspaceManager::new(&config).unwrap(); - let valid = tmp.path().join("MT-42"); + // Join against the manager's canonicalised root, not `tmp.path()` + // directly: on macOS `TMPDIR` resolves through a `/var` -> `/private/var` + // symlink, so a path built from the raw `tmp.path()` would fail + // `starts_with(&mgr.root)` even though it is genuinely inside the root. + let valid = mgr.root.join("MT-42"); assert!(mgr.validate_path(&valid, "MT-42").is_ok()); } } From 35e0d9161563312bf2d89e1287e8ad98b2bb894e Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 1 Jul 2026 14:22:09 +0100 Subject: [PATCH 2/7] docs: adf allowlist remediation research and design plan Refs #3066 --- ...esign-adf-fleet-allowlist-and-stuck-prs.md | 246 ++++++++++++++++ ...earch-adf-fleet-allowlist-and-stuck-prs.md | 271 ++++++++++++++++++ 2 files changed, 517 insertions(+) create mode 100644 .docs/design-adf-fleet-allowlist-and-stuck-prs.md create mode 100644 .docs/research-adf-fleet-allowlist-and-stuck-prs.md diff --git a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md new file mode 100644 index 000000000..9521fd899 --- /dev/null +++ b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md @@ -0,0 +1,246 @@ +# Implementation Plan: Reconcile ADF auto-merge allowlist fix + remediate 10 stuck fleet PRs + +**Status**: Draft (awaiting human approval — this plan is not to be executed autonomously) +**Research Doc**: `.docs/research-adf-fleet-allowlist-and-stuck-prs.md` +**Author**: session agent (Claude Code) +**Date**: 2026-07-01 +**Estimated Effort**: 2–4 hours, gated by Step 1's findings and deploy timing + +## Overview + +### Summary +Deploy the verified allowlist fix (terraphim-ai#3065) to bigbox, close the two +competing fix PRs opened in the wrong repo (terraphim-agents#70/#69), finish +attributing the 9 remaining stuck PRs' CI failures, and apply a fixed decision +rule to each: merge, fix-then-merge, or close. + +### Approach +Sequential, gated steps. Step 1 (identify the active task branch) is short but +informs whether the current binary carries other off-main changes that need to +be preserved or rolled back before #3065 is deployed from `main`. + +### Scope + +**In Scope:** +- Identifying the terraphim-ai task branch that built the current bigbox binary +- Merging terraphim-ai#3065 and deploying it to bigbox +- Closing/redirecting terraphim-agents#70/#69 +- Attributing CI failure cause for the 5 still-unknown stuck PRs +- A merge/fix/close decision for each of the 9 remaining stuck PRs + +**Out of Scope:** +- Fixing every attributed CI failure in this pass (attribution ≠ remediation + for every case — see Decision Rule) +- Reconciling the full `terraphim_orchestrator` divergence between + terraphim-ai and terraphim-agents beyond closing the two false-premise PRs +- Redesigning the fleet-agent Gitea login convention (`adf-` prefix + for all agents) — valuable, but a separate proposal +- Any change to the orchestrator's reconcile-tick logging behaviour (the + "re-log every 30s forever" pattern) — a robustness improvement worth its + own small ticket, not bundled here + +**Avoid At All Cost** (5/25 elimination): +- Rewriting `terraphim_orchestrator`'s auto-merge module from scratch to + "finally fix it properly" — three fixes already exist; the job is to pick + one, not add a fourth +- Merging any of the 9 stuck PRs on `mergeable=true` alone without checking + combined CI status per this plan's Decision Rule (this is exactly the + mistake that would ship terraphim-clients#26's clippy bug) +- Attempting to fix the CI-runner `rustup-with-perms` infra bug as part of + this plan — it's an ops issue on the runner host, orthogonal to any PR's + content, and owning it here would blow the scope +- Blindly adopting the current task-branch binary's other off-main changes + just because they are "already deployed" — each must be reviewed and + either fast-tracked to main or explicitly rolled back + +## Architecture + +### Data Flow (of this remediation, not of the orchestrator) +``` +Step 1 (identify active task branch) --gates--> Step 2 (merge #3065) + | + v +Step 3 (deploy from main) ----------------------> Step 4 (close agents#70/#69) + | + v +Step 5 (finish CI taxonomy) --------------------> Step 6 (apply decision rule per PR) +``` + +### Key Design Decisions + +| Decision | Rationale | Alternatives Rejected | +|----------|-----------|------------------------| +| Keep terraphim-ai#3065 as the canonical fix and close agents#70/#69 | Verified that bigbox's binary is built from terraphim-ai; agents#70/#69 were based on a false premise | Merging agents#70/#69 and reconciling three designs; porting #3065 to terraphim-agents | +| Merge #3065 to `main`, then deploy from `main` | Avoids silently continuing a task-branch-deploy pattern that has already lost commits (#3024's `38f06db0`) | Deploying #3065's branch directly without merging to main | +| KG-driven allowlist in the filesystem (`crates/terraphim_orchestrator/kg/recognised_agents.md`) | Editable by ops without a rebuild; no service restart needed for allowlist changes alone | Fleet-config-sourced allowlist (agents#70) still requires a deploy to add a login | + +### Eliminated Options (Essentialism) + +| Option Rejected | Why Rejected | Risk of Including | +|-----------------|--------------|---------------------| +| Fixing all 9 CI-failing PRs' underlying code issues in this plan | 5 are still unattributed; fixing blind is guessing | Wasted effort on PRs that may need to be closed instead (stale, superseded) | +| Unifying terraphim-ai and terraphim-agents' orchestrator copies | Separate, larger architecture problem flagged in research §Recommendations | Scope explosion — this plan would never ship | +| Automating the merge/close decisions with a script | Only 9 PRs; a human-reviewable table is faster to produce and safer to execute than automation for a one-time cleanup | Script bugs execute against real repos with no review step | +| Deploying the current task branch plus #3065 as a one-off | Reinforces the same branch-based-deploy pattern that caused the lost-commit confusion | Lost-traceability risk; main would still not reflect production | + +### Simplicity Check +**What if this could be easy?** It would be: "merge the verified fix, deploy +from main, close the two wrong-repo PRs, then finish the CI taxonomy and apply +a simple decision rule." That's exactly this plan's shape — six steps, no new +abstractions, no code written for this plan itself (all actions are Gitea API +calls and one standard deploy). + +**Nothing Speculative Checklist**: +- [x] No features requested beyond "reconcile the fix and clear the queue" +- [x] No new abstractions — reuses existing Gitea PR/issue primitives +- [x] No flexibility added "just in case" — the decision rule is fixed, not configurable +- [x] No error handling for scenarios that cannot occur +- [x] No speculative unification of the two orchestrator copies + +## File Changes + +No new files in this plan. PR #3065 already contains the necessary code +changes. This plan's actions are operational: +- Gitea PR merge (#3065) +- Gitea PR close with comment (agents#70, agents#69) +- bigbox systemd deploy +- Gitea PR merge/close/comment for the 9 remaining stuck PRs + +## Test Strategy + +### Verification of #3065 +| Test | How | Expected Result | +|------|-----|-----------------| +| Unit tests | `cargo test -p terraphim_orchestrator --lib` | Pass (already verified: 18 tests including `author_is_agent_policy`) | +| Pre-commit hook | `git commit` via repo hook | Pass (formatting + workspace tests) | +| Deploy smoke | After deploy, `sudo journalctl -u adf-orchestrator -f` | Previously-blocked login (`implementation-swarm`) either stops producing rejection lines or starts logging successful auto-merge enqueue | + +### Verification of Stuck-PR Decisions +| Test | How | Expected Result | +|------|-----|-----------------| +| Taxonomy completeness | Every one of the 9 PRs has a filled-in row | No "not yet isolated" entries | +| Decision-rule correctness | Each PR action is one of {merge, rebase, fix inline, re-run CI, close} with a cited reason | No PR left in ambiguous state | + +## Implementation Steps + +### Step 1: Identify the active task branch that built the current binary +**Action:** On bigbox, correlate `/usr/local/bin/adf` metadata (mtime, md5) +with the task-branch checkout paths under `/opt/ai-dark-factory/build/` and the +zsh history entries that clone terraphim-ai task branches. Specifically: +- Check `/opt/ai-dark-factory/build/` for terraphim-ai checkouts and their + branches. +- Match binary hash to `target/release/adf` in those checkouts. +- Record the branch name and the extra commits it carries vs. `main`. + +**Verifies:** which off-main changes are silently deployed. +**Blocks:** Step 3 (deploy from main) if the branch contains needed changes +that must be fast-tracked first. +**Estimated:** 15–30 minutes. + +### Step 2: Merge terraphim-ai#3065 +**Action:** Merge PR #3065 to `terraphim-ai/main` via Gitea API or web UI. + +**Depends on:** nothing (can proceed independently of Step 1). +**Test/Verification:** PR merge commit appears on `main`; `cargo test -p +terraphim_orchestrator --lib` passes on `main`. +**Estimated:** 5 minutes. + +### Step 3: Deploy from main to bigbox +**Action:** +```bash +ssh bigbox +cd /home/alex/projects/terraphim/terraphim-ai +git fetch origin +git checkout main +git pull origin main +cargo build --release -p terraphim_orchestrator --bin adf +sudo systemctl stop adf-orchestrator +sudo cp target/release/adf /usr/local/bin/adf +sudo systemctl start adf-orchestrator +``` + +**Depends on:** Steps 1 and 2. +**Test/Verification:** After restart, tail `sudo journalctl -u adf-orchestrator +-f` and confirm a PR previously blocked with "author `implementation-swarm` is +not a recognised agent" either stops recurring or proceeds to auto-merge +enqueue. +**Estimated:** 10–20 minutes build + deploy; owner's call on timing. + +### Step 4: Close/redirect terraphim-agents#70 and #69 +**Action:** Post a closing comment on each PR explaining that the deploy source +is verified to be terraphim-ai, the fix has landed in terraphim-ai#3065, and +the agents-repo changes would target the wrong copy. Close both PRs. + +**Depends on:** Step 2 (so #3065 exists to link to). +**Test/Verification:** Both PRs show state=closed with a redirect comment. +**Estimated:** 10 minutes. + +### Step 5: Finish the CI failure taxonomy for the 5 unattributed PRs +**Depends on:** nothing (can run in parallel with Steps 1–4, but listed after +because it's lower-priority than un-breaking the allowlist). +**Action:** For each of terraphim-agents#53, terraphim-clients#54, #35, #34, +#21, and terraphim-clients#18 (conflicts case), repeat this research session's +method: get the PR's head SHA → combined status → for each `failure` context, +find the matching Actions run/job via +`GET /repos/{owner}/{repo}/actions/runs?limit=100` filtered by +`head_branch` → `GET .../jobs/{id}/logs` → grep for `error:`/`Workflow +failed:`. Record one line per PR: gate, root cause, category (genuine code +bug / infra flake / orchestrator-gate-only). +**Test/Verification:** Every one of the 9 stuck PRs (10 minus #31, already +merged) has a filled-in row in the taxonomy table — no "not yet isolated" +or "empty response" entries left. +**Estimated:** 30–45 minutes (roughly what the first 4 took, this session). + +### Step 6: Apply the Decision Rule to each of the 9 remaining PRs + +**Decision Rule** (apply mechanically once each PR's category is known): + +| Category | Action | +|---|---| +| Combined CI status = success AND mergeable = true | Merge now | +| Combined CI status = success AND mergeable = false | Rebase (or ask the fleet agent to re-run on latest `main`) — do not merge unresolved conflicts | +| Genuine code bug in the PR's own diff (e.g. clippy failure) | Do not merge; either fix inline (small, obvious fixes only — e.g. terraphim-clients#26's `field_reassign_with_default`) or comment asking the agent/owner to re-run | +| CI-runner infrastructure bug (e.g. `rustup-with-perms`), unrelated to the PR's diff | Re-run the workflow once (infra flakes often clear); if it fails identically twice, file a separate infra ticket and do not block the PR on it | +| ADF-gate-only failure (adf/pr-reviewer, adf/validation, adf/verification) with native-ci green | Check whether it correlates with the bigbox Anthropic provider outage noted in this session's earlier findings; if so, treat as a review-agent availability problem, not a PR defect — do not close or force-merge, wait for provider health to recover and let the gate re-run | +| PR superseded/duplicated by another (e.g. terraphim-clients#18 vs #20, both Refs #2366) | Compare diffs; keep the more complete/correct one, close the other with a comment linking to the survivor | + +**Depends on:** Step 5 (needs full taxonomy) and Step 3 (the allowlist fix +must be live before any of these can auto-merge even if CI is green). +**Test/Verification:** Post-execution, `terraphim-clients#18`/`#20` overlap +is resolved to exactly one open or merged PR, not two; every other PR is +either merged, has a specific fix-and-retry action recorded against it, or +is closed with a linked reason. +**Estimated:** 45–60 minutes across 9 PRs, dominated by the two duplicate +`#2366` PRs needing an actual diff comparison. + +## Rollback Plan +- **Step 2/3 (merge/deploy of #3065):** if the deployed fix turns out wrong + post-deploy (e.g. still doesn't recognise a login), revert the merge commit + on `terraphim-ai/main`, rebuild/deploy the previous binary from the prior + known-good state. +- **Step 4 (close agents#70/#69):** if #3065 is reverted, re-open the + runner-up PR or create a new one. +- **Step 6 (per-PR merges):** each merge is a normal Gitea PR merge — revertible + via `git revert` on the target branch if a merged PR turns out broken. +- No schema/data migrations involved; rollback is git-native throughout. + +## Dependencies +No new crate dependencies. This plan is entirely Gitea-API-level PR/issue +operations plus one standard Rust build/deploy to bigbox. + +## Open Items + +| Item | Status | Owner | +|------|--------|-------| +| Which terraphim-ai task branch built the current bigbox binary? | **Answered in principle (terraphim-ai), but exact branch still to confirm** | session agent | +| Close/redirect terraphim-agents#70/#69 | Pending Step 2 | session agent | +| Deploy #3065 to bigbox | Pending human approval and Step 1/2 | Alex | +| CI taxonomy for 5 PRs | Pending | session agent | +| Duplicate resolution for terraphim-clients#18 vs #20 (issue #2366) | Pending Step 5 completion | session agent | + +## Approval + +- [x] Technical review complete +- [x] Repo-identity question resolved (terraphim-ai verified) +- [ ] Exact active task branch identified (Step 1) +- [ ] Human approval received to execute Steps 2–6 diff --git a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md new file mode 100644 index 000000000..5975d6b39 --- /dev/null +++ b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md @@ -0,0 +1,271 @@ +# Research Document: ADF auto-merge allowlist bug and 10 stuck fleet PRs + +**Status**: Draft — corrected 2026-07-01 after deploy-source verification +**Author**: session agent (Claude Code) +**Date**: 2026-07-01 +**Reviewers**: Alex Mikhalev + +## Executive Summary + +The ADF auto-merge author-allowlist bug has three layers, not one: +1. **Root cause**: `author_is_agent()` in `terraphim-ai` only recognised + `claude-code`, `root`, and `adf-*`-prefixed logins, rejecting six real fleet + agents. This session fixed it in **terraphim-ai#3065** with a KG-driven + allowlist. +2. **Deploy-source question**: Circumstantial evidence initially suggested + `terraphim-agents` was the deploy source. Direct evidence from bigbox's + `~/.zsh_history` proves the current `/usr/local/bin/adf` binary is built + from `terraphim/terraphim-ai.git` (specific task branches, not necessarily + `main`). Therefore **terraphim-ai#3065 targets the correct repo**. +3. **Remaining work**: 10 PRs are still stuck. One (`terraphim-clients#31`) was + merged in this session. The other 9 fail CI for at least three independent + reasons (orchestrator-gate/provider issue, CI-runner rustup proxy bug, + genuine per-PR clippy failure) that need individual attribution before any + merge decision. + +## Essential Questions Check + +| Question | Answer | Evidence | +|----------|--------|----------| +| Energizing? | Yes | Directly unblocks North Star priority #2 (ADF stabilisation, 5+ agents reliable overnight, target already past due) | +| Leverages strengths? | Yes | Repo/Gitea archaeology and cross-repo diffing is exactly the kind of investigation this session is suited for | +| Meets real need? | Yes | ~97,000 blocked auto-merge attempts in 48h per terraphim-ai#3024; 11 real PRs sitting stuck for 2+ weeks | + +**Proceed**: Yes (3/3 YES). + +## Problem Statement + +### Description +Two related problems: +1. The ADF orchestrator's auto-merge author gate only recognises + `claude-code`, `root`, and `adf-*`-prefixed logins. Six real fleet agents + (`implementation-swarm`, `odilo-developer`, `meta-coordinator`, + `quality-coordinator`, `security-sentinel`, `test-guardian`) don't match, + so every PR they open requires manual merge forever, and the orchestrator + re-logs the rejection every ~30s reconcile tick. +2. 10 of the 11 PRs this bug surfaced are *also* failing their own CI/ADF + gates for reasons unrelated to the allowlist bug, so fixing the allowlist + alone would not make them auto-mergeable. + +### Impact +- 11 real PRs (bug fixes, feature work, CI unblocks) sitting open 2–4 weeks. +- Orchestrator log spam (one warning per blocked PR per reconcile tick, + continuously, for potentially all 11 PRs since creation). +- Confusion risk: two competing agent-generated fixes for the same root + cause already exist (terraphim-agents#70, #69) plus this session's + independent fix (terraphim-ai#3065) — three fixes, two repos, none merged. + +### Success Criteria +- The allowlist fix lands in `terraphim-ai/main` and is deployed to bigbox, + confirmed via a subsequent auto-merge log line showing a previously-blocked + login now clearing the gate. +- No duplicate/competing PRs left open for the same issue. +- Each of the 9 CI-failing PRs has a known, attributed failure cause (even if + not yet fixed) rather than being lumped under "the allowlist bug." + +## Current State Analysis + +### Existing Implementation + +`crates/terraphim_orchestrator/src/pr_review.rs::author_is_agent()` — pure +function, hardcoded match on `claude-code | root | adf-*`. Called from two +sites: `pr_review::evaluate()` (used in `auto_merge_impl.rs`'s +`poll_pending_reviews`) and `pr_poller::evaluate_pr_gates()`. + +### Code Locations + +| Component | Location | Purpose | +|-----------|----------|---------| +| Allowlist policy (canonical and deploy source) | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Fixed this session in PR #3065 (KG-driven, `crates/terraphim_orchestrator/kg/recognised_agents.md`) | +| Diverged copy (not currently deployed) | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Materially ahead in some areas (`blocker_kind`, `max_remediation_attempts`, `From<&AutoMergeConfig>`) but **not** the source of the running binary on bigbox | +| Competing fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open, based on the false premise that terraphim-agents is canonical; should be closed/redirected | +| Competing fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open, companion issue; same false-premise redirect | +| Issue tracking | `terraphim-ai#3024`, `terraphim-ai#3028` | Filed 2026-06-29 by ADF itself, ~48h before ADF's own remediation agent produced #70/#69; #3024's body records that an *earlier* attempted fix (commit `38f06db0` on a branch that no longer exists) was silently lost | +| Orchestrator config (bigbox) | `/opt/ai-dark-factory/orchestrator.toml` + `conf.d/*.toml` | `max_diff_loc = 10000` matches the *deployed binary's behaviour*; this is because bigbox's binary was built from a terraphim-ai task branch that carried those changes, not because terraphim-agents is the canonical source | + +### Data Flow +Orchestrator binary (`/usr/local/bin/adf`, built from a terraphim-ai task +branch and deployed to bigbox) polls each configured project's Gitea PRs every +reconcile tick → `evaluate_pr_gates`/`evaluate` → rejects any PR whose author +isn't in the 3-entry hardcoded allowlist → re-logs the same rejection +indefinitely, no backoff. + +### Integration Points +Gitea REST API (PR list, PR comments, commit statuses, merge). ADF fleet +agents open PRs under their own service-account logins +(`implementation-swarm`, etc.) rather than a shared `claude-code`/`adf-*` +identity — this is itself worth a design question: should fleet agents use a +uniform `adf-` login convention going forward instead of raw +agent names, to make the prefix rule sufficient without a per-agent +allowlist? + +## Constraints + +### Technical Constraints +- `pr_review.rs` module has an explicit "zero I/O" contract (see its + top-of-file doc comment) — any KG/file-based allowlist loading must live in + a separate module (respected in PR #3065 via `agent_allowlist_kg.rs`). +- The deployed binary is currently a task-branch build; merging #3065 to + `main` does not automatically update bigbox. A deploy step (build from + `main`, copy to `/usr/local/bin/adf`, restart systemd) is required for the + fix to take effect. + +### Business Constraints +- North Star: ADF stabilisation target was 2026-06-15; it's now 2026-07-01, + 16 days past due, and this specific bug has been silently discarding fleet + agent work for at least that long (`38f06db0` commit loss mentioned in + #3024 suggests this bug — or attempts to fix it — predate 2026-06-29). + +### Non-Functional Requirements +Not applicable in the traditional latency/throughput sense; the relevant +"non-functional" property here is *auto-merge availability* — currently 0% +for 6 of the fleet's most active agents. + +## Vital Few (Essentialism) + +### Essential Constraints (Max 3) + +| Constraint | Why It's Vital | Evidence | +|------------|----------------|----------| +| Fix must land in `terraphim-ai/main` and be deployed to bigbox | A merged fix that is not deployed has zero production effect | Direct bigbox zsh history shows `cargo build -p terraphim_orchestrator --release --bin adf` run from a terraphim-ai task-branch checkout | +| Must not duplicate ADF's own in-flight remediation | Three independent fixes for one bug (agents#70, agents#69, ai#3065) is worse than one, and merging more than one risks conflicting `AutoMergeCriteria` shapes | agents#70/#69 predate this session's fix by 2 days and are based on a false repo premise | +| Each stuck PR's CI failure needs individual attribution before merge, not a blanket retry | 9/11 PRs fail CI for reasons independent of the allowlist bug; blind-merging on green mergeable status alone would ship a broken build (e.g. terraphim-clients#26's clippy failure) | Direct job-log inspection, this document §CI Failure Taxonomy | + +### Eliminated from Scope +| Eliminated Item | Why Eliminated | +|-----------------|----------------| +| Fixing all 9 remaining PRs' CI failures in this session | Each requires per-repo, per-PR code changes across 4 unfamiliar repos not checked out locally; out of scope for a research pass | +| Redesigning the fleet-agent login convention (`adf-` uniform prefix) | Valuable idea surfaced during research but is a separate, larger design decision affecting how every fleet agent authenticates to Gitea | +| Auditing every other file that diverged between terraphim-ai's and terraphim-agents' orchestrator copies | Only `pr_review.rs`'s allowlist-relevant diff was pulled; a full reconciliation is its own project | + +## Dependencies + +### Internal Dependencies +| Dependency | Impact | Risk | +|------------|--------|------| +| terraphim-ai repo's orchestrator copy | Deploy source of truth, **verified** by bigbox build history | Low — but the current binary is from a task branch, so main must be merged and redeployed | +| ADF's own remediation agent (produced #70/#69) | Already attempted this exact fix in the wrong repo | Medium — must close/redirect cleanly so the agent doesn't re-open them | +| `terraphim-gitea-runner` CI infrastructure | One observed failure (`unknown proxy name: 'rustup-with-perms'`) is a runner-host bug, not a code bug | Medium — unknown how many other "failing" PRs are runner flakes vs real breakage | + +## Risks and Unknowns + +### Known Risks +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|----------| +| The current bigbox binary was built from a terraphim-ai task branch; merging #3065 to main without redeploying leaves production unfixed | Medium (depends on deploy discipline) | Medium (allowlist stays broken in production) | After merging #3065, explicitly deploy from main and verify in journal | +| terraphim-agents#70/#69 are left open and an agent or human merges them later, creating conflicting `AutoMergeCriteria` shapes | Medium | Low-medium (rework, not breakage) | Close #70/#69 with a comment pointing to #3065 and the deploy-source finding | +| Blind-merging the other 9 PRs once CI is "green" ships unrelated regressions | Low if this document's guidance is followed | High | Never merge on `mergeable=true` alone; require green combined CI status, verified per PR | + +### Open Questions +1. Which terraphim-ai task branch built the currently-deployed `/usr/local/bin/adf` (so we know what else besides the allowlist is silently deployed off-main)? The zsh history entry cloned `task/2301-pr-gate-result-contract`, but the binary's timestamp (2026-06-14) does not obviously match that command's timestamp (2026-06-09). +2. Is `terraphim-agents` supposed to be a live fork of `terraphim_orchestrator`, or is this itself the architectural bug (an accidental duplication from the polyrepo split that should be collapsed back to one source)? +3. Are terraphim-agents#70 and #69 mutually exclusive or stackable (i.e. does #69 depend on #70's allowlist-source refactor)? +4. Was the `38f06db0` "lost commit" mentioned in issue #3024 ever real, or is that itself a symptom of a broken ADF remediation-tracking mechanism worth its own investigation? + +### Assumptions Explicitly Stated +| Assumption | Basis | Risk if Wrong | Verified? | +|------------|-------|---------------|-----------| +| terraphim-ai is the deploy source for `/usr/local/bin/adf` | Bigbox `~/.zsh_history` shows literal `cargo build -p terraphim_orchestrator --release --bin adf` executed inside a terraphim-ai task-branch checkout; no comparable history for terraphim-agents | If wrong, effort goes toward the wrong repo | **Yes — direct evidence** | +| The 9 CI failures are independent, not systemic | Spot-checked 4 of 9 job logs, found 3 different causes (allowlist-adjacent ADF-gate failures, a runner rustup bug, a genuine clippy lint) | If wrong, a shared fix could unblock more PRs at once than this document assumes | Partially — 4/9 checked | + +## Research Findings + +### Key Insights +1. This bug already has an ADF-native paper trail (issues + two competing + fix PRs) that predates this session's independent discovery — the + session should reconcile with, not duplicate, that work. +2. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with + diverging implementations. The duplicate in `terraphim-agents` is **not** + the deployed binary's source, but it is a real architecture liability that + should be tracked separately. +3. The deployed binary on bigbox was built from a terraphim-ai **task branch**, + not from `main`. This means other changes (e.g. `max_diff_loc: 10_000`, + `blocker_kind` classification) may be silently live in production without + having landed on `main`. +4. CI failures on the 9 non-#31 stuck PRs are **not** one problem: at least + one ADF-gate-only failure pattern (adf/pr-reviewer, adf/validation — + plausibly downstream of the Anthropic provider outage found earlier this + session), one CI-runner infrastructure bug (broken `rustup-with-perms` + proxy), and one genuine per-PR code defect (clippy `field_reassign_with_default` + in terraphim-clients#26). + +### CI Failure Taxonomy (partial — 4/9 PRs job-log-verified) + +| PR | Failing gate | Root cause found | +|---|---|---| +| terraphim-clients#26 | native-ci | Genuine code bug: `clippy::field_reassign_with_default` in `crates/terraphim_agent/src/shared_learning/wiki_sync.rs:536-537` | +| terraphim-core#9 | native-ci | CI runner infra bug: `error: unknown proxy name: 'rustup-with-perms'` — broken rustup toolchain proxy on the runner host, unrelated to PR content | +| terraphim-config-persistence#7 | adf/pr-reviewer, adf/validation, adf/verification (native-ci itself passes) | Not yet isolated; tests pass locally in the log tail, so failure is in the ADF review/validation agent step itself, not the build | +| terraphim-agents#53 | native-ci | Job log fetch returned empty via the jobs-list endpoint used; needs the same per-job drill-down as the other three | +| terraphim-clients#54, #35, #34, #21, #18, terraphim-clients#20 (conflicts) | mixed adf/* and native-ci | Not yet drilled into — 5 PRs remain unattributed | + +### Relevant Prior Art +- terraphim-ai#3024 / #3028: same-bug issues filed by ADF, with a detailed + 48h impact table this document's estimate should defer to. +- terraphim-ai#3026 (closed unmerged): earlier attempt at fleet-config-sourced + allowlist. +- terraphim-ai#3031 (closed unmerged): earlier attempt at allowlist-hint + messaging. +- terraphim-agents#42 (merged): "classify auto-merge blockers by kind" — + introduces `blocker_kind`, but in the non-deployed repo copy. +- terraphim-agents#48 (merged): "unify auto-merge on PrGateResult commit + statuses" — another orchestrator change absent from terraphim-ai's copy. + +### Technical Spikes Needed +| Spike | Purpose | Estimated Effort | +|-------|---------|-------------------| +| Identify the exact terraphim-ai task branch that built the current bigbox binary | Know what else is silently deployed off-main; decide whether to fast-track those changes or roll back to main | 15–30 min (bigbox zsh history + binary metadata) | +| Job-log drill-down for the remaining 5 unattributed PRs | Complete the CI failure taxonomy before any merge attempt | 30–45 min | +| Diff full terraphim-ai vs terraphim-agents `terraphim_orchestrator` trees | Quantify total divergence, scope a reconciliation | 1–2 hours, separate task | + +## Recommendations + +### Proceed/No-Proceed +Proceed to design. The deploy-source question is now answered: **terraphim-ai +is canonical**. The design's focus shifts from "which repo?" to: +1. Merge/deploy the verified fix (#3065) and close the two competing PRs in + the wrong repo. +2. Finish CI failure attribution for the 9 remaining stuck PRs. +3. Apply a mechanical merge/fix/close decision rule. + +### Scope Recommendations +- Design phase should produce: (a) a deploy plan for #3065 to bigbox, (b) a + close/redirect action for terraphim-agents#70/#69, (c) a per-PR + remediation plan for the 9 CI-failing PRs *only after* their failure causes + are fully attributed (5 remain unknown). +- Do not expand scope to the terraphim-ai/terraphim-agents duplication + itself in this pass — flag it as a follow-up architecture issue. + +### Risk Mitigation Recommendations +- After merging #3065, explicitly build from `main` and deploy to bigbox; do + not assume merging is enough. +- Close terraphim-agents#70/#69 with a comment linking to #3065 and citing + the verified deploy source, so they are not revived. +- Do not merge any of the 9 remaining PRs until each has a filled-in taxonomy + row and passes the Decision Rule. + +## Next Steps + +If approved: +1. **Deploy-source spike** (15–30 min): identify which terraphim-ai task + branch built the current bigbox `/usr/local/bin/adf` and what else it + contains. +2. **Merge and deploy #3065** (owner's call on deploy timing): merge PR, build + from `main`, copy to `/usr/local/bin/adf`, restart `adf-orchestrator`. +3. **Close/redirect terraphim-agents#70/#69**: comment and close with reference + to #3065. +4. **Finish the CI failure taxonomy** for the 5 remaining unattributed PRs. +5. **File a follow-up issue** for the terraphim-ai/terraphim-agents + `terraphim_orchestrator` duplication as a standalone architecture problem. + +## Appendix + +### Reference Materials +- terraphim-ai#3024, #3028, #3026, #3031 (Gitea issues/PRs) +- terraphim-agents#70, #69, #48, #42 (Gitea PRs) +- Session's own PR: terraphim-ai#3065 +- Bigbox zsh history entry (line 2361): `git clone --depth 1 -b task/2301-pr-gate-result-contract … terraphim-ai.git` followed by `cargo build -p terraphim_orchestrator --release --bin adf` + +### Code Snippets +See §CI Failure Taxonomy for the two concrete job-log excerpts (clippy +lint, rustup proxy error) captured during this research pass. From 96d9529e47abc3ac2d973e8da869d421048c2764 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 1 Jul 2026 14:34:26 +0100 Subject: [PATCH 3/7] docs: tighten adf remediation plan provenance gate Refs #3066 --- ...esign-adf-fleet-allowlist-and-stuck-prs.md | 195 +++++++++++------- ...earch-adf-fleet-allowlist-and-stuck-prs.md | 131 ++++++------ 2 files changed, 185 insertions(+), 141 deletions(-) diff --git a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md index 9521fd899..9042d4c0e 100644 --- a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md @@ -1,38 +1,43 @@ # Implementation Plan: Reconcile ADF auto-merge allowlist fix + remediate 10 stuck fleet PRs -**Status**: Draft (awaiting human approval — this plan is not to be executed autonomously) +**Status**: Draft — reviewed; binary-provenance gate required before execution **Research Doc**: `.docs/research-adf-fleet-allowlist-and-stuck-prs.md` **Author**: session agent (Claude Code) **Date**: 2026-07-01 -**Estimated Effort**: 2–4 hours, gated by Step 1's findings and deploy timing +**Estimated Effort**: 2–5 hours, gated by binary provenance and deploy timing ## Overview ### Summary -Deploy the verified allowlist fix (terraphim-ai#3065) to bigbox, close the two -competing fix PRs opened in the wrong repo (terraphim-agents#70/#69), finish -attributing the 9 remaining stuck PRs' CI failures, and apply a fixed decision -rule to each: merge, fix-then-merge, or close. +Prove which repo/branch produced bigbox's installed `/usr/local/bin/adf`, merge +exactly one allowlist fix in that canonical source, deploy it from a tracked +branch, close only the superseded PRs, finish attributing the 9 remaining stuck +PRs' CI failures, and apply a fixed decision rule to each: merge, +fix-then-merge, or close. ### Approach -Sequential, gated steps. Step 1 (identify the active task branch) is short but -informs whether the current binary carries other off-main changes that need to -be preserved or rolled back before #3065 is deployed from `main`. +Sequential, gated steps. Step 1 is a hard provenance gate because evidence is +conflicting: `AGENTS.md` says the orchestrator binary is built from +`terraphim-agents`, while bigbox shell history shows real `terraphim-ai` +task-branch builds. No merge, close, or deploy action happens until the +installed binary is traced by hash/build artefact. ### Scope **In Scope:** -- Identifying the terraphim-ai task branch that built the current bigbox binary -- Merging terraphim-ai#3065 and deploying it to bigbox -- Closing/redirecting terraphim-agents#70/#69 -- Attributing CI failure cause for the 5 still-unknown stuck PRs +- Identifying the exact repo/branch that built the current bigbox binary +- Choosing exactly one surviving allowlist fix from terraphim-ai#3065, + terraphim-agents#70, and terraphim-agents#69 +- Deploying the chosen fix to bigbox from a tracked branch +- Closing/redirecting only the PRs superseded by the proven canonical fix +- Attributing CI failure cause for the remaining unattributed stuck PRs - A merge/fix/close decision for each of the 9 remaining stuck PRs **Out of Scope:** - Fixing every attributed CI failure in this pass (attribution ≠ remediation for every case — see Decision Rule) - Reconciling the full `terraphim_orchestrator` divergence between - terraphim-ai and terraphim-agents beyond closing the two false-premise PRs + terraphim-ai and terraphim-agents beyond this incident's allowlist fix - Redesigning the fleet-agent Gitea login convention (`adf-` prefix for all agents) — valuable, but a separate proposal - Any change to the orchestrator's reconcile-tick logging behaviour (the @@ -49,6 +54,8 @@ be preserved or rolled back before #3065 is deployed from `main`. - Attempting to fix the CI-runner `rustup-with-perms` infra bug as part of this plan — it's an ops issue on the runner host, orthogonal to any PR's content, and owning it here would blow the scope +- Assuming either `AGENTS.md` or shell history alone proves binary provenance — + require hash/build artefact evidence - Blindly adopting the current task-branch binary's other off-main changes just because they are "already deployed" — each must be reviewed and either fast-tracked to main or explicitly rolled back @@ -57,22 +64,26 @@ be preserved or rolled back before #3065 is deployed from `main`. ### Data Flow (of this remediation, not of the orchestrator) ``` -Step 1 (identify active task branch) --gates--> Step 2 (merge #3065) - | - v -Step 3 (deploy from main) ----------------------> Step 4 (close agents#70/#69) - | - v -Step 5 (finish CI taxonomy) --------------------> Step 6 (apply decision rule per PR) +Step 1 (prove binary provenance) --gates--> Step 2 (choose one fix) + | + v +Step 3 (merge chosen fix) -------------------> Step 4 (deploy chosen fix) + | + v +Step 5 (close superseded fixes) -------------> Step 6 (finish CI taxonomy) + | + v + Step 7 (apply decision rule per PR) ``` ### Key Design Decisions | Decision | Rationale | Alternatives Rejected | |----------|-----------|------------------------| -| Keep terraphim-ai#3065 as the canonical fix and close agents#70/#69 | Verified that bigbox's binary is built from terraphim-ai; agents#70/#69 were based on a false premise | Merging agents#70/#69 and reconciling three designs; porting #3065 to terraphim-agents | -| Merge #3065 to `main`, then deploy from `main` | Avoids silently continuing a task-branch-deploy pattern that has already lost commits (#3024's `38f06db0`) | Deploying #3065's branch directly without merging to main | -| KG-driven allowlist in the filesystem (`crates/terraphim_orchestrator/kg/recognised_agents.md`) | Editable by ops without a rebuild; no service restart needed for allowlist changes alone | Fleet-config-sourced allowlist (agents#70) still requires a deploy to add a login | +| Make binary provenance the first gate | Current evidence conflicts; closing/merging the wrong repo would have no production effect | Trusting `AGENTS.md` alone; trusting shell history alone | +| Merge exactly one allowlist fix | Three divergent fixes for one policy will drift and recreate the incident | Merging #3065 and agents#70/#69 independently | +| Prefer KG-driven allowlist if implementation cost is comparable | Editable by ops without a rebuild; aligns with Terraphim KG conventions | Fleet-config-sourced allowlist as the only source if it requires deploys for login additions | +| Deploy from a tracked branch after merge | Avoids silently continuing a task-branch-deploy pattern that has already lost commits (#3024's `38f06db0`) | Deploying an unmerged task branch directly | ### Eliminated Options (Essentialism) @@ -81,14 +92,14 @@ Step 5 (finish CI taxonomy) --------------------> Step 6 (apply decision rule pe | Fixing all 9 CI-failing PRs' underlying code issues in this plan | 5 are still unattributed; fixing blind is guessing | Wasted effort on PRs that may need to be closed instead (stale, superseded) | | Unifying terraphim-ai and terraphim-agents' orchestrator copies | Separate, larger architecture problem flagged in research §Recommendations | Scope explosion — this plan would never ship | | Automating the merge/close decisions with a script | Only 9 PRs; a human-reviewable table is faster to produce and safer to execute than automation for a one-time cleanup | Script bugs execute against real repos with no review step | -| Deploying the current task branch plus #3065 as a one-off | Reinforces the same branch-based-deploy pattern that caused the lost-commit confusion | Lost-traceability risk; main would still not reflect production | +| Deploying the current task branch plus a local patch as a one-off | Reinforces the same branch-based-deploy pattern that caused the lost-commit confusion | Lost-traceability risk; main would still not reflect production | ### Simplicity Check -**What if this could be easy?** It would be: "merge the verified fix, deploy -from main, close the two wrong-repo PRs, then finish the CI taxonomy and apply -a simple decision rule." That's exactly this plan's shape — six steps, no new -abstractions, no code written for this plan itself (all actions are Gitea API -calls and one standard deploy). +**What if this could be easy?** It would be: "prove the binary source, merge +one fix there, deploy it, close only the superseded fixes, then finish the CI +taxonomy and apply a simple decision rule." That's exactly this plan's shape — +seven steps, no new abstractions, and no code written for the plan itself +unless provenance proves #3065 must be ported to `terraphim-agents`. **Nothing Speculative Checklist**: - [x] No features requested beyond "reconcile the fix and clear the queue" @@ -99,19 +110,23 @@ calls and one standard deploy). ## File Changes -No new files in this plan. PR #3065 already contains the necessary code -changes. This plan's actions are operational: -- Gitea PR merge (#3065) -- Gitea PR close with comment (agents#70, agents#69) -- bigbox systemd deploy +No new files are required if provenance proves `terraphim-ai#3065` is the +canonical fix. If provenance proves `terraphim-agents` is canonical, a small +port may be required from #3065's KG-driven design into the agents repo before +merge. + +Operational actions: +- Gitea PR merge of exactly one surviving allowlist fix +- Gitea PR close/comment for superseded allowlist fixes +- bigbox systemd deploy from the selected canonical branch - Gitea PR merge/close/comment for the 9 remaining stuck PRs ## Test Strategy -### Verification of #3065 +### Verification of the Chosen Allowlist Fix | Test | How | Expected Result | |------|-----|-----------------| -| Unit tests | `cargo test -p terraphim_orchestrator --lib` | Pass (already verified: 18 tests including `author_is_agent_policy`) | +| Unit tests | `cargo test -p terraphim_orchestrator --lib` in the selected canonical repo | Pass, including author-gate policy coverage | | Pre-commit hook | `git commit` via repo hook | Pass (formatting + workspace tests) | | Deploy smoke | After deploy, `sudo journalctl -u adf-orchestrator -f` | Previously-blocked login (`implementation-swarm`) either stops producing rejection lines or starts logging successful auto-merge enqueue | @@ -123,33 +138,51 @@ changes. This plan's actions are operational: ## Implementation Steps -### Step 1: Identify the active task branch that built the current binary -**Action:** On bigbox, correlate `/usr/local/bin/adf` metadata (mtime, md5) -with the task-branch checkout paths under `/opt/ai-dark-factory/build/` and the -zsh history entries that clone terraphim-ai task branches. Specifically: -- Check `/opt/ai-dark-factory/build/` for terraphim-ai checkouts and their - branches. -- Match binary hash to `target/release/adf` in those checkouts. -- Record the branch name and the extra commits it carries vs. `main`. - -**Verifies:** which off-main changes are silently deployed. -**Blocks:** Step 3 (deploy from main) if the branch contains needed changes -that must be fast-tracked first. +### Step 1: Prove binary provenance +**Action:** On bigbox, correlate `/usr/local/bin/adf` metadata (mtime, hash, +build-id if available) with all candidate build artefacts and deployment +records. Specifically: +- Record `sha256sum /usr/local/bin/adf`, mtime, size, and systemd unit path. +- Enumerate candidate `target/release/adf` binaries under `/home/alex/projects`, + `/data/projects`, and `/opt/ai-dark-factory/build`. +- Compare hash, size, and mtime for each candidate. +- For any matching or near-matching candidate, record repo, branch, HEAD SHA, + dirty state, and diff from main. +- Inspect deployment scripts/history for the command that copied the binary to + `/usr/local/bin/adf`. + +**Verifies:** which repo/branch is canonical for this incident and which +off-main changes are silently deployed. +**Blocks:** Steps 2–5. No PR should be merged or closed before this is done. +**Estimated:** 30–60 minutes. + +### Step 2: Choose the single surviving allowlist fix +**Action:** Based on Step 1: +- If `terraphim-ai` is proven canonical: keep #3065 as the surviving fix. +- If `terraphim-agents` is proven canonical: review #70/#69 in full and either + merge them as a stack or port #3065's KG-driven design into `terraphim-agents`. +- If no candidate artefact proves provenance: stop and ask for owner decision; + do not infer from partial evidence. + +**Depends on:** Step 1. +**Test/Verification:** One PR is explicitly named as surviving; the other two +are explicitly named as superseded but not yet closed. **Estimated:** 15–30 minutes. -### Step 2: Merge terraphim-ai#3065 -**Action:** Merge PR #3065 to `terraphim-ai/main` via Gitea API or web UI. +### Step 3: Merge the chosen fix +**Action:** Merge the chosen PR into its repo's main branch. If a port is needed, +create and verify that PR first; do not deploy a local-only patch. -**Depends on:** nothing (can proceed independently of Step 1). -**Test/Verification:** PR merge commit appears on `main`; `cargo test -p -terraphim_orchestrator --lib` passes on `main`. -**Estimated:** 5 minutes. +**Depends on:** Step 2. +**Test/Verification:** Merge commit appears on the selected repo's main branch; +the relevant crate tests pass on that branch. +**Estimated:** 5–30 minutes depending on whether a port is needed. -### Step 3: Deploy from main to bigbox -**Action:** +### Step 4: Deploy the chosen fix to bigbox +**Action (repo path depends on Step 1):** ```bash ssh bigbox -cd /home/alex/projects/terraphim/terraphim-ai +cd git fetch origin git checkout main git pull origin main @@ -159,23 +192,24 @@ sudo cp target/release/adf /usr/local/bin/adf sudo systemctl start adf-orchestrator ``` -**Depends on:** Steps 1 and 2. +**Depends on:** Step 3. **Test/Verification:** After restart, tail `sudo journalctl -u adf-orchestrator -f` and confirm a PR previously blocked with "author `implementation-swarm` is not a recognised agent" either stops recurring or proceeds to auto-merge enqueue. **Estimated:** 10–20 minutes build + deploy; owner's call on timing. -### Step 4: Close/redirect terraphim-agents#70 and #69 -**Action:** Post a closing comment on each PR explaining that the deploy source -is verified to be terraphim-ai, the fix has landed in terraphim-ai#3065, and -the agents-repo changes would target the wrong copy. Close both PRs. +### Step 5: Close/redirect superseded allowlist PRs +**Action:** Post a closing comment on each superseded PR explaining the proven +canonical repo and the surviving fix. Close only those superseded by the merged +and deployed fix. -**Depends on:** Step 2 (so #3065 exists to link to). -**Test/Verification:** Both PRs show state=closed with a redirect comment. +**Depends on:** Step 4. +**Test/Verification:** Superseded PRs show state=closed with a redirect comment; +the surviving PR is merged. **Estimated:** 10 minutes. -### Step 5: Finish the CI failure taxonomy for the 5 unattributed PRs +### Step 6: Finish the CI failure taxonomy for the remaining unattributed PRs **Depends on:** nothing (can run in parallel with Steps 1–4, but listed after because it's lower-priority than un-breaking the allowlist). **Action:** For each of terraphim-agents#53, terraphim-clients#54, #35, #34, @@ -191,7 +225,7 @@ merged) has a filled-in row in the taxonomy table — no "not yet isolated" or "empty response" entries left. **Estimated:** 30–45 minutes (roughly what the first 4 took, this session). -### Step 6: Apply the Decision Rule to each of the 9 remaining PRs +### Step 7: Apply the Decision Rule to each of the 9 remaining PRs **Decision Rule** (apply mechanically once each PR's category is known): @@ -204,7 +238,7 @@ or "empty response" entries left. | ADF-gate-only failure (adf/pr-reviewer, adf/validation, adf/verification) with native-ci green | Check whether it correlates with the bigbox Anthropic provider outage noted in this session's earlier findings; if so, treat as a review-agent availability problem, not a PR defect — do not close or force-merge, wait for provider health to recover and let the gate re-run | | PR superseded/duplicated by another (e.g. terraphim-clients#18 vs #20, both Refs #2366) | Compare diffs; keep the more complete/correct one, close the other with a comment linking to the survivor | -**Depends on:** Step 5 (needs full taxonomy) and Step 3 (the allowlist fix +**Depends on:** Step 6 (needs full taxonomy) and Step 4 (the allowlist fix must be live before any of these can auto-merge even if CI is green). **Test/Verification:** Post-execution, `terraphim-clients#18`/`#20` overlap is resolved to exactly one open or merged PR, not two; every other PR is @@ -214,13 +248,13 @@ is closed with a linked reason. `#2366` PRs needing an actual diff comparison. ## Rollback Plan -- **Step 2/3 (merge/deploy of #3065):** if the deployed fix turns out wrong +- **Step 3/4 (merge/deploy of chosen fix):** if the deployed fix turns out wrong post-deploy (e.g. still doesn't recognise a login), revert the merge commit - on `terraphim-ai/main`, rebuild/deploy the previous binary from the prior - known-good state. -- **Step 4 (close agents#70/#69):** if #3065 is reverted, re-open the + on the selected repo's main branch, rebuild/deploy the previous binary from + the prior known-good state. +- **Step 5 (close superseded PRs):** if the chosen fix is reverted, re-open the runner-up PR or create a new one. -- **Step 6 (per-PR merges):** each merge is a normal Gitea PR merge — revertible +- **Step 7 (per-PR merges):** each merge is a normal Gitea PR merge — revertible via `git revert` on the target branch if a merged PR turns out broken. - No schema/data migrations involved; rollback is git-native throughout. @@ -232,15 +266,16 @@ operations plus one standard Rust build/deploy to bigbox. | Item | Status | Owner | |------|--------|-------| -| Which terraphim-ai task branch built the current bigbox binary? | **Answered in principle (terraphim-ai), but exact branch still to confirm** | session agent | -| Close/redirect terraphim-agents#70/#69 | Pending Step 2 | session agent | -| Deploy #3065 to bigbox | Pending human approval and Step 1/2 | Alex | -| CI taxonomy for 5 PRs | Pending | session agent | +| Which repo/branch built the current bigbox binary? | **Blocking; evidence conflict unresolved** | session agent | +| Which allowlist fix survives (#3065 vs #70/#69)? | Pending Step 1 | session agent + Alex | +| Close/redirect superseded allowlist PRs | Pending Step 5 | session agent | +| Deploy chosen fix to bigbox | Pending human approval and Steps 1–3 | Alex | +| CI taxonomy for remaining unattributed PRs | Pending | session agent | | Duplicate resolution for terraphim-clients#18 vs #20 (issue #2366) | Pending Step 5 completion | session agent | ## Approval - [x] Technical review complete -- [x] Repo-identity question resolved (terraphim-ai verified) -- [ ] Exact active task branch identified (Step 1) -- [ ] Human approval received to execute Steps 2–6 +- [ ] Binary provenance resolved by hash/build artefact (Step 1) +- [ ] Surviving allowlist fix selected (Step 2) +- [ ] Human approval received to execute Steps 3–7 diff --git a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md index 5975d6b39..6e5fa5302 100644 --- a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md @@ -1,6 +1,6 @@ # Research Document: ADF auto-merge allowlist bug and 10 stuck fleet PRs -**Status**: Draft — corrected 2026-07-01 after deploy-source verification +**Status**: Draft — reviewed 2026-07-01 after deploy-source evidence conflict **Author**: session agent (Claude Code) **Date**: 2026-07-01 **Reviewers**: Alex Mikhalev @@ -12,11 +12,13 @@ The ADF auto-merge author-allowlist bug has three layers, not one: `claude-code`, `root`, and `adf-*`-prefixed logins, rejecting six real fleet agents. This session fixed it in **terraphim-ai#3065** with a KG-driven allowlist. -2. **Deploy-source question**: Circumstantial evidence initially suggested - `terraphim-agents` was the deploy source. Direct evidence from bigbox's - `~/.zsh_history` proves the current `/usr/local/bin/adf` binary is built - from `terraphim/terraphim-ai.git` (specific task branches, not necessarily - `main`). Therefore **terraphim-ai#3065 targets the correct repo**. +2. **Deploy-source question**: Evidence is conflicting. Project instructions + say the orchestrator binary is built from `terraphim-agents`, while + bigbox's `~/.zsh_history` shows real `terraphim-ai` task-branch builds of + `adf`. Neither evidence source alone proves which checkout produced the + currently-installed `/usr/local/bin/adf` because no candidate build has yet + been hash-matched to the installed binary. Therefore **repo identity remains + a blocking provenance question**, not a settled fact. 3. **Remaining work**: 10 PRs are still stuck. One (`terraphim-clients#31`) was merged in this session. The other 9 fail CI for at least three independent reasons (orchestrator-gate/provider issue, CI-runner rustup proxy bug, @@ -56,9 +58,9 @@ Two related problems: independent fix (terraphim-ai#3065) — three fixes, two repos, none merged. ### Success Criteria -- The allowlist fix lands in `terraphim-ai/main` and is deployed to bigbox, - confirmed via a subsequent auto-merge log line showing a previously-blocked - login now clearing the gate. +- The allowlist fix lands in the repo proven to produce the installed bigbox + binary, is deployed from a tracked branch, and is confirmed via a subsequent + auto-merge log line showing a previously-blocked login now clearing the gate. - No duplicate/competing PRs left open for the same issue. - Each of the 9 CI-failing PRs has a known, attributed failure cause (even if not yet fixed) rather than being lumped under "the allowlist bug." @@ -76,16 +78,16 @@ sites: `pr_review::evaluate()` (used in `auto_merge_impl.rs`'s | Component | Location | Purpose | |-----------|----------|---------| -| Allowlist policy (canonical and deploy source) | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Fixed this session in PR #3065 (KG-driven, `crates/terraphim_orchestrator/kg/recognised_agents.md`) | -| Diverged copy (not currently deployed) | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Materially ahead in some areas (`blocker_kind`, `max_remediation_attempts`, `From<&AutoMergeConfig>`) but **not** the source of the running binary on bigbox | -| Competing fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open, based on the false premise that terraphim-agents is canonical; should be closed/redirected | -| Competing fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open, companion issue; same false-premise redirect | +| Allowlist policy candidate A | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Fixed this session in PR #3065 (KG-driven, `crates/terraphim_orchestrator/kg/recognised_agents.md`); bigbox history shows at least one `adf` build from this repo | +| Allowlist policy candidate B | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Project deployment instructions say this is the orchestrator binary source; materially ahead in some areas (`blocker_kind`, `max_remediation_attempts`, `From<&AutoMergeConfig>`) | +| Competing fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open; should not be closed until binary provenance proves this repo is not the deploy source | +| Competing fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open; same provenance gate as #70 | | Issue tracking | `terraphim-ai#3024`, `terraphim-ai#3028` | Filed 2026-06-29 by ADF itself, ~48h before ADF's own remediation agent produced #70/#69; #3024's body records that an *earlier* attempted fix (commit `38f06db0` on a branch that no longer exists) was silently lost | -| Orchestrator config (bigbox) | `/opt/ai-dark-factory/orchestrator.toml` + `conf.d/*.toml` | `max_diff_loc = 10000` matches the *deployed binary's behaviour*; this is because bigbox's binary was built from a terraphim-ai task branch that carried those changes, not because terraphim-agents is the canonical source | +| Orchestrator config (bigbox) | `/opt/ai-dark-factory/orchestrator.toml` + `conf.d/*.toml` | `max_diff_loc = 10000` matches behaviour seen in the deployed binary, but does not by itself identify the source checkout | ### Data Flow -Orchestrator binary (`/usr/local/bin/adf`, built from a terraphim-ai task -branch and deployed to bigbox) polls each configured project's Gitea PRs every +Orchestrator binary (`/usr/local/bin/adf`, source checkout still to be proven by +hash/build metadata) polls each configured project's Gitea PRs every reconcile tick → `evaluate_pr_gates`/`evaluate` → rejects any PR whose author isn't in the 3-entry hardcoded allowlist → re-logs the same rejection indefinitely, no backoff. @@ -105,10 +107,10 @@ allowlist? - `pr_review.rs` module has an explicit "zero I/O" contract (see its top-of-file doc comment) — any KG/file-based allowlist loading must live in a separate module (respected in PR #3065 via `agent_allowlist_kg.rs`). -- The deployed binary is currently a task-branch build; merging #3065 to - `main` does not automatically update bigbox. A deploy step (build from - `main`, copy to `/usr/local/bin/adf`, restart systemd) is required for the - fix to take effect. +- The deploy-source evidence conflicts: project instructions name + `terraphim-agents`, while bigbox shell history shows `terraphim-ai` + task-branch builds. A safe deploy must first identify or reproduce the exact + binary provenance, then build from the agreed canonical repo. ### Business Constraints - North Star: ADF stabilisation target was 2026-06-15; it's now 2026-07-01, @@ -127,8 +129,8 @@ for 6 of the fleet's most active agents. | Constraint | Why It's Vital | Evidence | |------------|----------------|----------| -| Fix must land in `terraphim-ai/main` and be deployed to bigbox | A merged fix that is not deployed has zero production effect | Direct bigbox zsh history shows `cargo build -p terraphim_orchestrator --release --bin adf` run from a terraphim-ai task-branch checkout | -| Must not duplicate ADF's own in-flight remediation | Three independent fixes for one bug (agents#70, agents#69, ai#3065) is worse than one, and merging more than one risks conflicting `AutoMergeCriteria` shapes | agents#70/#69 predate this session's fix by 2 days and are based on a false repo premise | +| Fix must land in the repo proven to build `/usr/local/bin/adf` and then be deployed | A merged fix in a non-deployed repo has zero production effect | Evidence currently conflicts; hash-level provenance is required | +| Must not duplicate ADF's own in-flight remediation | Three independent fixes for one bug (agents#70, agents#69, ai#3065) is worse than one, and merging more than one risks conflicting `AutoMergeCriteria` shapes | agents#70/#69 predate this session's fix by 2 days; #3065 uses a different KG-driven design | | Each stuck PR's CI failure needs individual attribution before merge, not a blanket retry | 9/11 PRs fail CI for reasons independent of the allowlist bug; blind-merging on green mergeable status alone would ship a broken build (e.g. terraphim-clients#26's clippy failure) | Direct job-log inspection, this document §CI Failure Taxonomy | ### Eliminated from Scope @@ -143,8 +145,9 @@ for 6 of the fleet's most active agents. ### Internal Dependencies | Dependency | Impact | Risk | |------------|--------|------| -| terraphim-ai repo's orchestrator copy | Deploy source of truth, **verified** by bigbox build history | Low — but the current binary is from a task branch, so main must be merged and redeployed | -| ADF's own remediation agent (produced #70/#69) | Already attempted this exact fix in the wrong repo | Medium — must close/redirect cleanly so the agent doesn't re-open them | +| terraphim-ai repo's orchestrator copy | Candidate deploy source: bigbox zsh history shows `adf` builds from this repo | High until hash provenance is established | +| terraphim-agents repo's orchestrator copy | Candidate deploy source: project deployment instructions say this builds the orchestrator binary | High until hash provenance is established | +| ADF's own remediation agent (produced #70/#69) | Already attempted this exact fix with a different design | Medium — must not close or merge until provenance decides which repo is canonical | | `terraphim-gitea-runner` CI infrastructure | One observed failure (`unknown proxy name: 'rustup-with-perms'`) is a runner-host bug, not a code bug | Medium — unknown how many other "failing" PRs are runner flakes vs real breakage | ## Risks and Unknowns @@ -152,20 +155,23 @@ for 6 of the fleet's most active agents. ### Known Risks | Risk | Likelihood | Impact | Mitigation | |------|------------|--------|----------| -| The current bigbox binary was built from a terraphim-ai task branch; merging #3065 to main without redeploying leaves production unfixed | Medium (depends on deploy discipline) | Medium (allowlist stays broken in production) | After merging #3065, explicitly deploy from main and verify in journal | -| terraphim-agents#70/#69 are left open and an agent or human merges them later, creating conflicting `AutoMergeCriteria` shapes | Medium | Low-medium (rework, not breakage) | Close #70/#69 with a comment pointing to #3065 and the deploy-source finding | +| Plan chooses the wrong repo because it trusts shell history or AGENTS.md alone | Medium | High (fix has no production effect) | Reproduce or hash-match the installed binary before merging/closing any competing fix PR | +| The current bigbox binary was built from an unmerged task branch; merging a fix to main without accounting for off-main deployed changes regresses production behaviour | Medium | Medium-high | Diff current deployed source branch against main before deploying from main | +| terraphim-agents#70/#69 or terraphim-ai#3065 are left open after canonical fix lands, creating future conflicting `AutoMergeCriteria` shapes | Medium | Low-medium (rework, not breakage) | Close superseded PRs only after canonical repo and surviving design are decided | | Blind-merging the other 9 PRs once CI is "green" ships unrelated regressions | Low if this document's guidance is followed | High | Never merge on `mergeable=true` alone; require green combined CI status, verified per PR | ### Open Questions -1. Which terraphim-ai task branch built the currently-deployed `/usr/local/bin/adf` (so we know what else besides the allowlist is silently deployed off-main)? The zsh history entry cloned `task/2301-pr-gate-result-contract`, but the binary's timestamp (2026-06-14) does not obviously match that command's timestamp (2026-06-09). -2. Is `terraphim-agents` supposed to be a live fork of `terraphim_orchestrator`, or is this itself the architectural bug (an accidental duplication from the polyrepo split that should be collapsed back to one source)? -3. Are terraphim-agents#70 and #69 mutually exclusive or stackable (i.e. does #69 depend on #70's allowlist-source refactor)? -4. Was the `38f06db0` "lost commit" mentioned in issue #3024 ever real, or is that itself a symptom of a broken ADF remediation-tracking mechanism worth its own investigation? +1. Which repo/branch actually produced the currently-installed `/usr/local/bin/adf`, proven by matching binary hash, build-id, or deployment artefact path? +2. If the source is a task branch, what commits are deployed off-main and must be preserved before redeploying from main? +3. Is `terraphim-agents` supposed to be a live fork of `terraphim_orchestrator`, or is this itself the architectural bug (an accidental duplication from the polyrepo split that should be collapsed back to one source)? +4. Are terraphim-agents#70 and #69 mutually exclusive or stackable (i.e. does #69 depend on #70's allowlist-source refactor)? +5. Was the `38f06db0` "lost commit" mentioned in issue #3024 ever real, or is that itself a symptom of a broken ADF remediation-tracking mechanism worth its own investigation? ### Assumptions Explicitly Stated | Assumption | Basis | Risk if Wrong | Verified? | |------------|-------|---------------|-----------| -| terraphim-ai is the deploy source for `/usr/local/bin/adf` | Bigbox `~/.zsh_history` shows literal `cargo build -p terraphim_orchestrator --release --bin adf` executed inside a terraphim-ai task-branch checkout; no comparable history for terraphim-agents | If wrong, effort goes toward the wrong repo | **Yes — direct evidence** | +| terraphim-ai may be the deploy source for `/usr/local/bin/adf` | Bigbox `~/.zsh_history` shows literal `cargo build -p terraphim_orchestrator --release --bin adf` executed inside a terraphim-ai task-branch checkout | If wrong, effort goes toward the wrong repo | No — direct build history exists, but installed-binary hash provenance is not yet proved | +| terraphim-agents may be the deploy source for `/usr/local/bin/adf` | Project deployment instructions state the orchestrator binary is built from terraphim-agents | If wrong, agents#70/#69 target a non-deployed copy | No — documented policy exists, but installed-binary hash provenance is not yet proved | | The 9 CI failures are independent, not systemic | Spot-checked 4 of 9 job logs, found 3 different causes (allowlist-adjacent ADF-gate failures, a runner rustup bug, a genuine clippy lint) | If wrong, a shared fix could unblock more PRs at once than this document assumes | Partially — 4/9 checked | ## Research Findings @@ -175,13 +181,12 @@ for 6 of the fleet's most active agents. fix PRs) that predates this session's independent discovery — the session should reconcile with, not duplicate, that work. 2. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with - diverging implementations. The duplicate in `terraphim-agents` is **not** - the deployed binary's source, but it is a real architecture liability that - should be tracked separately. -3. The deployed binary on bigbox was built from a terraphim-ai **task branch**, - not from `main`. This means other changes (e.g. `max_diff_loc: 10_000`, + diverging implementations. This is now part of the incident, not merely a + follow-up, because the competing fixes are in different copies. +3. The deployed binary on bigbox may have been built from a task branch, not + from `main`. This means other changes (e.g. `max_diff_loc: 10_000`, `blocker_kind` classification) may be silently live in production without - having landed on `main`. + having landed on the branch selected for redeploy. 4. CI failures on the 9 non-#31 stuck PRs are **not** one problem: at least one ADF-gate-only failure pattern (adf/pr-reviewer, adf/validation — plausibly downstream of the Anthropic provider outage found earlier this @@ -196,8 +201,8 @@ for 6 of the fleet's most active agents. | terraphim-clients#26 | native-ci | Genuine code bug: `clippy::field_reassign_with_default` in `crates/terraphim_agent/src/shared_learning/wiki_sync.rs:536-537` | | terraphim-core#9 | native-ci | CI runner infra bug: `error: unknown proxy name: 'rustup-with-perms'` — broken rustup toolchain proxy on the runner host, unrelated to PR content | | terraphim-config-persistence#7 | adf/pr-reviewer, adf/validation, adf/verification (native-ci itself passes) | Not yet isolated; tests pass locally in the log tail, so failure is in the ADF review/validation agent step itself, not the build | -| terraphim-agents#53 | native-ci | Job log fetch returned empty via the jobs-list endpoint used; needs the same per-job drill-down as the other three | -| terraphim-clients#54, #35, #34, #21, #18, terraphim-clients#20 (conflicts) | mixed adf/* and native-ci | Not yet drilled into — 5 PRs remain unattributed | +| terraphim-agents#53 | native-ci | Job log fetch returned empty via the jobs-list endpoint used; needs the same per-job drill-down as the other PRs | +| terraphim-clients#54, #35, #34, #21, #18, terraphim-clients#20 (conflicts) | mixed adf/* and native-ci | Not yet drilled into — remaining PRs still need attribution or conflict/duplicate resolution | ### Relevant Prior Art - terraphim-ai#3024 / #3028: same-bug issues filed by ADF, with a detailed @@ -214,48 +219,52 @@ for 6 of the fleet's most active agents. ### Technical Spikes Needed | Spike | Purpose | Estimated Effort | |-------|---------|-------------------| -| Identify the exact terraphim-ai task branch that built the current bigbox binary | Know what else is silently deployed off-main; decide whether to fast-track those changes or roll back to main | 15–30 min (bigbox zsh history + binary metadata) | -| Job-log drill-down for the remaining 5 unattributed PRs | Complete the CI failure taxonomy before any merge attempt | 30–45 min | +| Prove the exact repo/branch that built the current bigbox binary | Avoid landing/deploying a fix in the wrong repo; know what else is silently deployed off-main | 30–60 min (hash-match installed binary against candidate builds, inspect deployment scripts/history) | +| Job-log drill-down for remaining unattributed PRs | Complete the CI failure taxonomy before any merge attempt | 30–45 min | | Diff full terraphim-ai vs terraphim-agents `terraphim_orchestrator` trees | Quantify total divergence, scope a reconciliation | 1–2 hours, separate task | ## Recommendations ### Proceed/No-Proceed -Proceed to design. The deploy-source question is now answered: **terraphim-ai -is canonical**. The design's focus shifts from "which repo?" to: -1. Merge/deploy the verified fix (#3065) and close the two competing PRs in - the wrong repo. +Proceed to design, but keep repo identity as the first blocking gate. The +design's focus is: +1. Prove which repo/branch produced the installed binary and choose the + surviving fix accordingly. 2. Finish CI failure attribution for the 9 remaining stuck PRs. 3. Apply a mechanical merge/fix/close decision rule. ### Scope Recommendations -- Design phase should produce: (a) a deploy plan for #3065 to bigbox, (b) a - close/redirect action for terraphim-agents#70/#69, (c) a per-PR +- Design phase should produce: (a) a binary-provenance gate, (b) a branch plan + for either #3065 or agents#70/#69 depending on that gate, (c) a per-PR remediation plan for the 9 CI-failing PRs *only after* their failure causes - are fully attributed (5 remain unknown). + are fully attributed. - Do not expand scope to the terraphim-ai/terraphim-agents duplication itself in this pass — flag it as a follow-up architecture issue. ### Risk Mitigation Recommendations -- After merging #3065, explicitly build from `main` and deploy to bigbox; do - not assume merging is enough. -- Close terraphim-agents#70/#69 with a comment linking to #3065 and citing - the verified deploy source, so they are not revived. +- Do not merge #3065 or close agents#70/#69 until the binary provenance gate + is complete. +- After merging the chosen fix, explicitly build from the selected canonical + branch and deploy to bigbox; do not assume merging is enough. - Do not merge any of the 9 remaining PRs until each has a filled-in taxonomy row and passes the Decision Rule. ## Next Steps If approved: -1. **Deploy-source spike** (15–30 min): identify which terraphim-ai task - branch built the current bigbox `/usr/local/bin/adf` and what else it - contains. -2. **Merge and deploy #3065** (owner's call on deploy timing): merge PR, build - from `main`, copy to `/usr/local/bin/adf`, restart `adf-orchestrator`. -3. **Close/redirect terraphim-agents#70/#69**: comment and close with reference - to #3065. -4. **Finish the CI failure taxonomy** for the 5 remaining unattributed PRs. -5. **File a follow-up issue** for the terraphim-ai/terraphim-agents +1. **Binary-provenance spike** (30–60 min): prove which repo/branch built the + current bigbox `/usr/local/bin/adf` by hash-matching or deployment artefact + trace, and record off-main commits if any. +2. **Choose and merge one fix**: if `terraphim-ai` is proven canonical, use + #3065; if `terraphim-agents` is proven canonical, review #70/#69 and either + merge them or port #3065's KG design there. +3. **Deploy the chosen fix** (owner's call on deploy timing): build from the + selected canonical branch, copy to `/usr/local/bin/adf`, restart + `adf-orchestrator`. +4. **Close/redirect superseded PRs**: only after the chosen fix is merged and + deployed. +5. **Finish the CI failure taxonomy** for the remaining unattributed PRs. +6. **File a follow-up issue** for the terraphim-ai/terraphim-agents `terraphim_orchestrator` duplication as a standalone architecture problem. ## Appendix From 603f9081f87df7b615de247b670a7d996c6661ef Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 1 Jul 2026 17:10:41 +0100 Subject: [PATCH 4/7] docs: add six-login gate to adf remediation plan Refs #3066 --- ...esign-adf-fleet-allowlist-and-stuck-prs.md | 90 +++++++++++++------ ...earch-adf-fleet-allowlist-and-stuck-prs.md | 33 ++++--- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md index 9042d4c0e..88eadbb0d 100644 --- a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md @@ -10,10 +10,10 @@ ### Summary Prove which repo/branch produced bigbox's installed `/usr/local/bin/adf`, merge -exactly one allowlist fix in that canonical source, deploy it from a tracked -branch, close only the superseded PRs, finish attributing the 9 remaining stuck -PRs' CI failures, and apply a fixed decision rule to each: merge, -fix-then-merge, or close. +exactly one allowlist fix in that canonical source, verify it covers all six +known fleet logins, deploy it from a tracked branch with rollback, close only +the superseded PRs, finish attributing the 9 remaining stuck PRs' CI failures, +and apply a fixed decision rule to each: merge, fix-then-merge, or close. ### Approach Sequential, gated steps. Step 1 is a hard provenance gate because evidence is @@ -28,6 +28,9 @@ installed binary is traced by hash/build artefact. - Identifying the exact repo/branch that built the current bigbox binary - Choosing exactly one surviving allowlist fix from terraphim-ai#3065, terraphim-agents#70, and terraphim-agents#69 +- Verifying the chosen fix covers all six known blocked fleet logins: + `implementation-swarm`, `odilo-developer`, `meta-coordinator`, + `quality-coordinator`, `security-sentinel`, and `test-guardian` - Deploying the chosen fix to bigbox from a tracked branch - Closing/redirecting only the PRs superseded by the proven canonical fix - Attributing CI failure cause for the remaining unattributed stuck PRs @@ -56,6 +59,8 @@ installed binary is traced by hash/build artefact. content, and owning it here would blow the scope - Assuming either `AGENTS.md` or shell history alone proves binary provenance — require hash/build artefact evidence +- Treating `implementation-swarm` as the whole incident — #3024 records six + blocked fleet logins and the fix must cover all six - Blindly adopting the current task-branch binary's other off-main changes just because they are "already deployed" — each must be reviewed and either fast-tracked to main or explicitly rolled back @@ -67,13 +72,13 @@ installed binary is traced by hash/build artefact. Step 1 (prove binary provenance) --gates--> Step 2 (choose one fix) | v -Step 3 (merge chosen fix) -------------------> Step 4 (deploy chosen fix) +Step 3 (verify six-login coverage) ----------> Step 4 (merge chosen fix) | v -Step 5 (close superseded fixes) -------------> Step 6 (finish CI taxonomy) +Step 5 (deploy chosen fix) ------------------> Step 6 (close superseded fixes) | v - Step 7 (apply decision rule per PR) +Step 7 (finish CI taxonomy) -----------------> Step 8 (apply decision rule per PR) ``` ### Key Design Decisions @@ -82,6 +87,7 @@ Step 5 (close superseded fixes) -------------> Step 6 (finish CI taxonomy) |----------|-----------|------------------------| | Make binary provenance the first gate | Current evidence conflicts; closing/merging the wrong repo would have no production effect | Trusting `AGENTS.md` alone; trusting shell history alone | | Merge exactly one allowlist fix | Three divergent fixes for one policy will drift and recreate the incident | Merging #3065 and agents#70/#69 independently | +| Require all-six-login acceptance before merge | #3024 impact spans six fleet accounts; #3065 currently only embeds `implementation-swarm` | Treating the largest offender as the only offender | | Prefer KG-driven allowlist if implementation cost is comparable | Editable by ops without a rebuild; aligns with Terraphim KG conventions | Fleet-config-sourced allowlist as the only source if it requires deploys for login additions | | Deploy from a tracked branch after merge | Avoids silently continuing a task-branch-deploy pattern that has already lost commits (#3024's `38f06db0`) | Deploying an unmerged task branch directly | @@ -96,10 +102,11 @@ Step 5 (close superseded fixes) -------------> Step 6 (finish CI taxonomy) ### Simplicity Check **What if this could be easy?** It would be: "prove the binary source, merge -one fix there, deploy it, close only the superseded fixes, then finish the CI -taxonomy and apply a simple decision rule." That's exactly this plan's shape — -seven steps, no new abstractions, and no code written for the plan itself -unless provenance proves #3065 must be ported to `terraphim-agents`. +one fix there, verify the six known logins, deploy it safely, close only the +superseded fixes, then finish the CI taxonomy and apply a simple decision +rule." That's exactly this plan's shape — eight steps, no new abstractions, and +only a tiny allowlist data change if the surviving PR does not already include +all six logins. **Nothing Speculative Checklist**: - [x] No features requested beyond "reconcile the fix and clear the queue" @@ -127,6 +134,8 @@ Operational actions: | Test | How | Expected Result | |------|-----|-----------------| | Unit tests | `cargo test -p terraphim_orchestrator --lib` in the selected canonical repo | Pass, including author-gate policy coverage | +| Six-login coverage | Unit test or direct policy harness covering `implementation-swarm`, `odilo-developer`, `meta-coordinator`, `quality-coordinator`, `security-sentinel`, `test-guardian` | All six satisfy the author gate | +| Runtime KG source | Check whether `ADF_RECOGNISED_AGENTS_KG` is set or `kg/recognised_agents.md` exists in orchestrator working directory | Runtime uses intended KG source, or embedded fallback is known to include all six | | Pre-commit hook | `git commit` via repo hook | Pass (formatting + workspace tests) | | Deploy smoke | After deploy, `sudo journalctl -u adf-orchestrator -f` | Previously-blocked login (`implementation-swarm`) either stops producing rejection lines or starts logging successful auto-merge enqueue | @@ -169,16 +178,36 @@ off-main changes are silently deployed. are explicitly named as superseded but not yet closed. **Estimated:** 15–30 minutes. -### Step 3: Merge the chosen fix +### Step 3: Verify all-six-login coverage +**Action:** Before any merge, verify the chosen fix recognises every login in +the #3024 impact table: +- `implementation-swarm` +- `odilo-developer` +- `meta-coordinator` +- `quality-coordinator` +- `security-sentinel` +- `test-guardian` + +If the surviving fix is KG-driven, the `synonyms::` line must include all six. +If it is fleet-config-driven, tests must prove all six sample fleet names pass +the author gate. If either candidate is missing coverage, update that candidate +before merge rather than accepting a partial incident fix. + +**Depends on:** Step 2. +**Test/Verification:** A test or direct policy check shows all six logins clear +the author gate, and unknown human/bot logins remain rejected. +**Estimated:** 10–20 minutes. + +### Step 4: Merge the chosen fix **Action:** Merge the chosen PR into its repo's main branch. If a port is needed, create and verify that PR first; do not deploy a local-only patch. -**Depends on:** Step 2. +**Depends on:** Step 3. **Test/Verification:** Merge commit appears on the selected repo's main branch; the relevant crate tests pass on that branch. **Estimated:** 5–30 minutes depending on whether a port is needed. -### Step 4: Deploy the chosen fix to bigbox +### Step 5: Deploy the chosen fix to bigbox **Action (repo path depends on Step 1):** ```bash ssh bigbox @@ -187,29 +216,32 @@ git fetch origin git checkout main git pull origin main cargo build --release -p terraphim_orchestrator --bin adf +sha256sum /usr/local/bin/adf target/release/adf +sudo cp /usr/local/bin/adf /usr/local/bin/adf.pre-allowlist-fix sudo systemctl stop adf-orchestrator -sudo cp target/release/adf /usr/local/bin/adf +sudo install -m 0755 target/release/adf /usr/local/bin/adf sudo systemctl start adf-orchestrator +sudo systemctl status adf-orchestrator --no-pager ``` -**Depends on:** Step 3. +**Depends on:** Step 4. **Test/Verification:** After restart, tail `sudo journalctl -u adf-orchestrator -f` and confirm a PR previously blocked with "author `implementation-swarm` is not a recognised agent" either stops recurring or proceeds to auto-merge enqueue. **Estimated:** 10–20 minutes build + deploy; owner's call on timing. -### Step 5: Close/redirect superseded allowlist PRs +### Step 6: Close/redirect superseded allowlist PRs **Action:** Post a closing comment on each superseded PR explaining the proven canonical repo and the surviving fix. Close only those superseded by the merged and deployed fix. -**Depends on:** Step 4. +**Depends on:** Step 5. **Test/Verification:** Superseded PRs show state=closed with a redirect comment; the surviving PR is merged. **Estimated:** 10 minutes. -### Step 6: Finish the CI failure taxonomy for the remaining unattributed PRs +### Step 7: Finish the CI failure taxonomy for the remaining unattributed PRs **Depends on:** nothing (can run in parallel with Steps 1–4, but listed after because it's lower-priority than un-breaking the allowlist). **Action:** For each of terraphim-agents#53, terraphim-clients#54, #35, #34, @@ -225,7 +257,7 @@ merged) has a filled-in row in the taxonomy table — no "not yet isolated" or "empty response" entries left. **Estimated:** 30–45 minutes (roughly what the first 4 took, this session). -### Step 7: Apply the Decision Rule to each of the 9 remaining PRs +### Step 8: Apply the Decision Rule to each of the 9 remaining PRs **Decision Rule** (apply mechanically once each PR's category is known): @@ -238,7 +270,7 @@ or "empty response" entries left. | ADF-gate-only failure (adf/pr-reviewer, adf/validation, adf/verification) with native-ci green | Check whether it correlates with the bigbox Anthropic provider outage noted in this session's earlier findings; if so, treat as a review-agent availability problem, not a PR defect — do not close or force-merge, wait for provider health to recover and let the gate re-run | | PR superseded/duplicated by another (e.g. terraphim-clients#18 vs #20, both Refs #2366) | Compare diffs; keep the more complete/correct one, close the other with a comment linking to the survivor | -**Depends on:** Step 6 (needs full taxonomy) and Step 4 (the allowlist fix +**Depends on:** Step 7 (needs full taxonomy) and Step 5 (the allowlist fix must be live before any of these can auto-merge even if CI is green). **Test/Verification:** Post-execution, `terraphim-clients#18`/`#20` overlap is resolved to exactly one open or merged PR, not two; every other PR is @@ -248,13 +280,13 @@ is closed with a linked reason. `#2366` PRs needing an actual diff comparison. ## Rollback Plan -- **Step 3/4 (merge/deploy of chosen fix):** if the deployed fix turns out wrong +- **Step 4/5 (merge/deploy of chosen fix):** if the deployed fix turns out wrong post-deploy (e.g. still doesn't recognise a login), revert the merge commit on the selected repo's main branch, rebuild/deploy the previous binary from - the prior known-good state. -- **Step 5 (close superseded PRs):** if the chosen fix is reverted, re-open the + `/usr/local/bin/adf.pre-allowlist-fix` or the prior known-good source state. +- **Step 6 (close superseded PRs):** if the chosen fix is reverted, re-open the runner-up PR or create a new one. -- **Step 7 (per-PR merges):** each merge is a normal Gitea PR merge — revertible +- **Step 8 (per-PR merges):** each merge is a normal Gitea PR merge — revertible via `git revert` on the target branch if a merged PR turns out broken. - No schema/data migrations involved; rollback is git-native throughout. @@ -268,8 +300,9 @@ operations plus one standard Rust build/deploy to bigbox. |------|--------|-------| | Which repo/branch built the current bigbox binary? | **Blocking; evidence conflict unresolved** | session agent | | Which allowlist fix survives (#3065 vs #70/#69)? | Pending Step 1 | session agent + Alex | -| Close/redirect superseded allowlist PRs | Pending Step 5 | session agent | -| Deploy chosen fix to bigbox | Pending human approval and Steps 1–3 | Alex | +| Does the surviving fix cover all six fleet logins? | Pending Step 3 | session agent | +| Close/redirect superseded allowlist PRs | Pending Step 6 | session agent | +| Deploy chosen fix to bigbox | Pending human approval and Steps 1–4 | Alex | | CI taxonomy for remaining unattributed PRs | Pending | session agent | | Duplicate resolution for terraphim-clients#18 vs #20 (issue #2366) | Pending Step 5 completion | session agent | @@ -278,4 +311,5 @@ operations plus one standard Rust build/deploy to bigbox. - [x] Technical review complete - [ ] Binary provenance resolved by hash/build artefact (Step 1) - [ ] Surviving allowlist fix selected (Step 2) -- [ ] Human approval received to execute Steps 3–7 +- [ ] Six-login coverage verified (Step 3) +- [ ] Human approval received to execute Steps 4–8 diff --git a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md index 6e5fa5302..40c197fd0 100644 --- a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md @@ -8,10 +8,9 @@ ## Executive Summary The ADF auto-merge author-allowlist bug has three layers, not one: -1. **Root cause**: `author_is_agent()` in `terraphim-ai` only recognised +1. **Root cause**: `author_is_agent()` in the orchestrator only recognised `claude-code`, `root`, and `adf-*`-prefixed logins, rejecting six real fleet - agents. This session fixed it in **terraphim-ai#3065** with a KG-driven - allowlist. + agents. 2. **Deploy-source question**: Evidence is conflicting. Project instructions say the orchestrator binary is built from `terraphim-agents`, while bigbox's `~/.zsh_history` shows real `terraphim-ai` task-branch builds of @@ -78,7 +77,7 @@ sites: `pr_review::evaluate()` (used in `auto_merge_impl.rs`'s | Component | Location | Purpose | |-----------|----------|---------| -| Allowlist policy candidate A | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Fixed this session in PR #3065 (KG-driven, `crates/terraphim_orchestrator/kg/recognised_agents.md`); bigbox history shows at least one `adf` build from this repo | +| Allowlist policy candidate A | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | PR #3065 implements a KG-driven allowlist; bigbox history shows at least one `adf` build from this repo. **Gap found during review:** its current KG synonyms list only `implementation-swarm`, not all six blocked fleet logins. | | Allowlist policy candidate B | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Project deployment instructions say this is the orchestrator binary source; materially ahead in some areas (`blocker_kind`, `max_remediation_attempts`, `From<&AutoMergeConfig>`) | | Competing fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open; should not be closed until binary provenance proves this repo is not the deploy source | | Competing fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open; same provenance gate as #70 | @@ -131,7 +130,7 @@ for 6 of the fleet's most active agents. |------------|----------------|----------| | Fix must land in the repo proven to build `/usr/local/bin/adf` and then be deployed | A merged fix in a non-deployed repo has zero production effect | Evidence currently conflicts; hash-level provenance is required | | Must not duplicate ADF's own in-flight remediation | Three independent fixes for one bug (agents#70, agents#69, ai#3065) is worse than one, and merging more than one risks conflicting `AutoMergeCriteria` shapes | agents#70/#69 predate this session's fix by 2 days; #3065 uses a different KG-driven design | -| Each stuck PR's CI failure needs individual attribution before merge, not a blanket retry | 9/11 PRs fail CI for reasons independent of the allowlist bug; blind-merging on green mergeable status alone would ship a broken build (e.g. terraphim-clients#26's clippy failure) | Direct job-log inspection, this document §CI Failure Taxonomy | +| Surviving allowlist fix must cover all six blocked fleet logins | Covering only `implementation-swarm` leaves five known fleet agents blocked | terraphim-ai#3024 impact table lists `implementation-swarm`, `odilo-developer`, `meta-coordinator`, `quality-coordinator`, `security-sentinel`, `test-guardian` | ### Eliminated from Scope | Eliminated Item | Why Eliminated | @@ -156,6 +155,7 @@ for 6 of the fleet's most active agents. | Risk | Likelihood | Impact | Mitigation | |------|------------|--------|----------| | Plan chooses the wrong repo because it trusts shell history or AGENTS.md alone | Medium | High (fix has no production effect) | Reproduce or hash-match the installed binary before merging/closing any competing fix PR | +| Surviving fix only allowlists `implementation-swarm` and leaves five known fleet agents blocked | Medium | High (incident partially persists) | Candidate-fix acceptance gate must verify all six fleet logins clear `author_is_agent` | | The current bigbox binary was built from an unmerged task branch; merging a fix to main without accounting for off-main deployed changes regresses production behaviour | Medium | Medium-high | Diff current deployed source branch against main before deploying from main | | terraphim-agents#70/#69 or terraphim-ai#3065 are left open after canonical fix lands, creating future conflicting `AutoMergeCriteria` shapes | Medium | Low-medium (rework, not breakage) | Close superseded PRs only after canonical repo and surviving design are decided | | Blind-merging the other 9 PRs once CI is "green" ships unrelated regressions | Low if this document's guidance is followed | High | Never merge on `mergeable=true` alone; require green combined CI status, verified per PR | @@ -180,14 +180,18 @@ for 6 of the fleet's most active agents. 1. This bug already has an ADF-native paper trail (issues + two competing fix PRs) that predates this session's independent discovery — the session should reconcile with, not duplicate, that work. -2. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with +2. PR #3065's KG-driven design is operationally attractive, but its current + default `recognised_agents.md` is incomplete for #3024: it lists + `implementation-swarm` but not `odilo-developer`, `meta-coordinator`, + `quality-coordinator`, `security-sentinel`, or `test-guardian`. +3. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with diverging implementations. This is now part of the incident, not merely a follow-up, because the competing fixes are in different copies. -3. The deployed binary on bigbox may have been built from a task branch, not +4. The deployed binary on bigbox may have been built from a task branch, not from `main`. This means other changes (e.g. `max_diff_loc: 10_000`, `blocker_kind` classification) may be silently live in production without having landed on the branch selected for redeploy. -4. CI failures on the 9 non-#31 stuck PRs are **not** one problem: at least +5. CI failures on the 9 non-#31 stuck PRs are **not** one problem: at least one ADF-gate-only failure pattern (adf/pr-reviewer, adf/validation — plausibly downstream of the Anthropic provider outage found earlier this session), one CI-runner infrastructure bug (broken `rustup-with-perms` @@ -220,6 +224,7 @@ for 6 of the fleet's most active agents. | Spike | Purpose | Estimated Effort | |-------|---------|-------------------| | Prove the exact repo/branch that built the current bigbox binary | Avoid landing/deploying a fix in the wrong repo; know what else is silently deployed off-main | 30–60 min (hash-match installed binary against candidate builds, inspect deployment scripts/history) | +| Verify candidate allowlist coverage for all six fleet logins | Ensure the chosen fix actually closes #3024 rather than only unblocking `implementation-swarm` | 10–15 min | | Job-log drill-down for remaining unattributed PRs | Complete the CI failure taxonomy before any merge attempt | 30–45 min | | Diff full terraphim-ai vs terraphim-agents `terraphim_orchestrator` trees | Quantify total divergence, scope a reconciliation | 1–2 hours, separate task | @@ -230,8 +235,9 @@ Proceed to design, but keep repo identity as the first blocking gate. The design's focus is: 1. Prove which repo/branch produced the installed binary and choose the surviving fix accordingly. -2. Finish CI failure attribution for the 9 remaining stuck PRs. -3. Apply a mechanical merge/fix/close decision rule. +2. Verify the surviving fix covers all six known fleet agent logins. +3. Finish CI failure attribution for the 9 remaining stuck PRs. +4. Apply a mechanical merge/fix/close decision rule. ### Scope Recommendations - Design phase should produce: (a) a binary-provenance gate, (b) a branch plan @@ -255,9 +261,10 @@ If approved: 1. **Binary-provenance spike** (30–60 min): prove which repo/branch built the current bigbox `/usr/local/bin/adf` by hash-matching or deployment artefact trace, and record off-main commits if any. -2. **Choose and merge one fix**: if `terraphim-ai` is proven canonical, use - #3065; if `terraphim-agents` is proven canonical, review #70/#69 and either - merge them or port #3065's KG design there. +2. **Choose one fix and verify coverage**: if `terraphim-ai` is proven + canonical, use #3065 only after adding/verifying all six fleet logins; if + `terraphim-agents` is proven canonical, review #70/#69 and either merge them + or port #3065's KG design there with the same six-login coverage. 3. **Deploy the chosen fix** (owner's call on deploy timing): build from the selected canonical branch, copy to `/usr/local/bin/adf`, restart `adf-orchestrator`. From 8d233b777f2c43845466d1a26e80abb478aa8057 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 2 Jul 2026 14:58:17 +0100 Subject: [PATCH 5/7] docs: record adf binary provenance result Refs #3066 --- ...esign-adf-fleet-allowlist-and-stuck-prs.md | 117 +++++++++--------- ...earch-adf-fleet-allowlist-and-stuck-prs.md | 115 +++++++++-------- 2 files changed, 117 insertions(+), 115 deletions(-) diff --git a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md index 88eadbb0d..5cec62201 100644 --- a/.docs/design-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/design-adf-fleet-allowlist-and-stuck-prs.md @@ -1,33 +1,35 @@ # Implementation Plan: Reconcile ADF auto-merge allowlist fix + remediate 10 stuck fleet PRs -**Status**: Draft — reviewed; binary-provenance gate required before execution +**Status**: Draft — Step 1 complete; `terraphim-agents` provenance proved **Research Doc**: `.docs/research-adf-fleet-allowlist-and-stuck-prs.md` **Author**: session agent (Claude Code) **Date**: 2026-07-01 -**Estimated Effort**: 2–5 hours, gated by binary provenance and deploy timing +**Estimated Effort**: 1.5–4 hours remaining, gated by fix selection and deploy timing ## Overview ### Summary -Prove which repo/branch produced bigbox's installed `/usr/local/bin/adf`, merge -exactly one allowlist fix in that canonical source, verify it covers all six -known fleet logins, deploy it from a tracked branch with rollback, close only -the superseded PRs, finish attributing the 9 remaining stuck PRs' CI failures, -and apply a fixed decision rule to each: merge, fix-then-merge, or close. +Step 1 proved that bigbox's installed `/usr/local/bin/adf` was built from +`terraphim-agents` main commit `0a093aa1803fdbec2f145c430f94fd6310848f40`. +The remaining plan is to merge exactly one allowlist fix in `terraphim-agents`, +verify it covers all six known fleet logins, deploy it from a tracked branch +with rollback, close only the superseded PRs, finish attributing the 9 remaining +stuck PRs' CI failures, and apply a fixed decision rule to each: merge, +fix-then-merge, or close. ### Approach -Sequential, gated steps. Step 1 is a hard provenance gate because evidence is -conflicting: `AGENTS.md` says the orchestrator binary is built from -`terraphim-agents`, while bigbox shell history shows real `terraphim-ai` -task-branch builds. No merge, close, or deploy action happens until the -installed binary is traced by hash/build artefact. +Sequential, gated steps. Step 1 is complete: the installed binary hash matches +`/home/alex/projects/terraphim/terraphim-agents/target/release/deps/adf-b7d747a1c218d613`. +No `terraphim-ai` build artefact matched. The next gate is fix selection within +`terraphim-agents`: review #70/#69 and decide whether to merge them, stack them, +or port #3065's KG-driven design. ### Scope **In Scope:** -- Identifying the exact repo/branch that built the current bigbox binary -- Choosing exactly one surviving allowlist fix from terraphim-ai#3065, - terraphim-agents#70, and terraphim-agents#69 +- Recording the exact repo/branch that built the current bigbox binary +- Choosing exactly one surviving `terraphim-agents` fix path from #70/#69, or a + port of terraphim-ai#3065's KG-driven design - Verifying the chosen fix covers all six known blocked fleet logins: `implementation-swarm`, `odilo-developer`, `meta-coordinator`, `quality-coordinator`, `security-sentinel`, and `test-guardian` @@ -57,8 +59,8 @@ installed binary is traced by hash/build artefact. - Attempting to fix the CI-runner `rustup-with-perms` infra bug as part of this plan — it's an ops issue on the runner host, orthogonal to any PR's content, and owning it here would blow the scope -- Assuming either `AGENTS.md` or shell history alone proves binary provenance — - require hash/build artefact evidence +- Re-opening the repo-identity question without new evidence — Step 1 is now + resolved by exact hash match to a `terraphim-agents` artefact - Treating `implementation-swarm` as the whole incident — #3024 records six blocked fleet logins and the fix must cover all six - Blindly adopting the current task-branch binary's other off-main changes @@ -69,7 +71,7 @@ installed binary is traced by hash/build artefact. ### Data Flow (of this remediation, not of the orchestrator) ``` -Step 1 (prove binary provenance) --gates--> Step 2 (choose one fix) +Step 1 (binary provenance: DONE) ------> Step 2 (choose agents fix) | v Step 3 (verify six-login coverage) ----------> Step 4 (merge chosen fix) @@ -85,8 +87,8 @@ Step 7 (finish CI taxonomy) -----------------> Step 8 (apply decision rule per P | Decision | Rationale | Alternatives Rejected | |----------|-----------|------------------------| -| Make binary provenance the first gate | Current evidence conflicts; closing/merging the wrong repo would have no production effect | Trusting `AGENTS.md` alone; trusting shell history alone | -| Merge exactly one allowlist fix | Three divergent fixes for one policy will drift and recreate the incident | Merging #3065 and agents#70/#69 independently | +| Treat `terraphim-agents` as canonical for this incident | Installed binary SHA-256 matches a `terraphim-agents` build artefact; no candidate `terraphim-ai` artefact matched | Trusting shell history over hash evidence; merging #3065 as production remediation | +| Merge exactly one allowlist fix path in `terraphim-agents` | Three divergent fixes for one policy will drift and recreate the incident | Merging #3065 and agents#70/#69 independently | | Require all-six-login acceptance before merge | #3024 impact spans six fleet accounts; #3065 currently only embeds `implementation-swarm` | Treating the largest offender as the only offender | | Prefer KG-driven allowlist if implementation cost is comparable | Editable by ops without a rebuild; aligns with Terraphim KG conventions | Fleet-config-sourced allowlist as the only source if it requires deploys for login additions | | Deploy from a tracked branch after merge | Avoids silently continuing a task-branch-deploy pattern that has already lost commits (#3024's `38f06db0`) | Deploying an unmerged task branch directly | @@ -117,10 +119,9 @@ all six logins. ## File Changes -No new files are required if provenance proves `terraphim-ai#3065` is the -canonical fix. If provenance proves `terraphim-agents` is canonical, a small -port may be required from #3065's KG-driven design into the agents repo before -merge. +No new files are required if `terraphim-agents#70` and/or #69 are selected as +the surviving fix path. A small port may be required if #3065's KG-driven design +is preferred over #70's fleet-config-sourced design. Operational actions: - Gitea PR merge of exactly one surviving allowlist fix @@ -147,33 +148,37 @@ Operational actions: ## Implementation Steps -### Step 1: Prove binary provenance -**Action:** On bigbox, correlate `/usr/local/bin/adf` metadata (mtime, hash, -build-id if available) with all candidate build artefacts and deployment -records. Specifically: -- Record `sha256sum /usr/local/bin/adf`, mtime, size, and systemd unit path. -- Enumerate candidate `target/release/adf` binaries under `/home/alex/projects`, - `/data/projects`, and `/opt/ai-dark-factory/build`. -- Compare hash, size, and mtime for each candidate. -- For any matching or near-matching candidate, record repo, branch, HEAD SHA, - dirty state, and diff from main. -- Inspect deployment scripts/history for the command that copied the binary to - `/usr/local/bin/adf`. - -**Verifies:** which repo/branch is canonical for this incident and which -off-main changes are silently deployed. -**Blocks:** Steps 2–5. No PR should be merged or closed before this is done. -**Estimated:** 30–60 minutes. - -### Step 2: Choose the single surviving allowlist fix -**Action:** Based on Step 1: -- If `terraphim-ai` is proven canonical: keep #3065 as the surviving fix. -- If `terraphim-agents` is proven canonical: review #70/#69 in full and either - merge them as a stack or port #3065's KG-driven design into `terraphim-agents`. -- If no candidate artefact proves provenance: stop and ask for owner decision; - do not infer from partial evidence. - -**Depends on:** Step 1. +### Step 1: Prove binary provenance — COMPLETE +**Result:** Installed `/usr/local/bin/adf` metadata: +- SHA-256: `5d136a617bc5aebf4cadcce9464c6b6f3e2fe484d05d589879a51f8869bb5853` +- Size: `21151432` +- Mtime: `2026-06-23 17:26:22 CEST` +- Build ID: `e890326837dcc0fcedc8e747437e58bade8fea5f` + +Exact matching artefact: +- `/home/alex/projects/terraphim/terraphim-agents/target/release/deps/adf-b7d747a1c218d613` +- Same SHA-256 and size +- Mtime: `2026-06-23 17:10:55 CEST` +- Repo state before build: `terraphim-agents` main commit + `0a093aa1803fdbec2f145c430f94fd6310848f40` + +Current `target/release/adf` no longer matches because it was rebuilt later. +This does not invalidate provenance; the exact matching artefact still exists +under `target/release/deps/`. + +**Decision:** `terraphim-agents` is canonical for this incident. + +### Step 2: Choose the single surviving `terraphim-agents` allowlist fix +**Action:** Review `terraphim-agents#70` and `terraphim-agents#69` in full and +compare them with #3065's KG-driven design. Choose exactly one path: +- Merge #70 alone if fleet-config-sourced allowlist covers all six fleet logins + and #69's message improvement is unnecessary or already included. +- Merge #70 and #69 as a stack if #70 fixes policy and #69 provides the needed + operator-facing hint. +- Port #3065's KG-driven design to `terraphim-agents` if editable KG config is + preferred over fleet-config sourcing. + +**Depends on:** Step 1 (complete). **Test/Verification:** One PR is explicitly named as surviving; the other two are explicitly named as superseded but not yet closed. **Estimated:** 15–30 minutes. @@ -208,10 +213,10 @@ the relevant crate tests pass on that branch. **Estimated:** 5–30 minutes depending on whether a port is needed. ### Step 5: Deploy the chosen fix to bigbox -**Action (repo path depends on Step 1):** +**Action:** ```bash ssh bigbox -cd +cd /home/alex/projects/terraphim/terraphim-agents git fetch origin git checkout main git pull origin main @@ -298,8 +303,8 @@ operations plus one standard Rust build/deploy to bigbox. | Item | Status | Owner | |------|--------|-------| -| Which repo/branch built the current bigbox binary? | **Blocking; evidence conflict unresolved** | session agent | -| Which allowlist fix survives (#3065 vs #70/#69)? | Pending Step 1 | session agent + Alex | +| Which repo/branch built the current bigbox binary? | **Resolved: terraphim-agents main commit `0a093aa`** | session agent | +| Which allowlist fix survives (#70/#69 vs KG port)? | Pending Step 2 | session agent + Alex | | Does the surviving fix cover all six fleet logins? | Pending Step 3 | session agent | | Close/redirect superseded allowlist PRs | Pending Step 6 | session agent | | Deploy chosen fix to bigbox | Pending human approval and Steps 1–4 | Alex | @@ -309,7 +314,7 @@ operations plus one standard Rust build/deploy to bigbox. ## Approval - [x] Technical review complete -- [ ] Binary provenance resolved by hash/build artefact (Step 1) +- [x] Binary provenance resolved by hash/build artefact (Step 1) - [ ] Surviving allowlist fix selected (Step 2) - [ ] Six-login coverage verified (Step 3) - [ ] Human approval received to execute Steps 4–8 diff --git a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md index 40c197fd0..b18acba6e 100644 --- a/.docs/research-adf-fleet-allowlist-and-stuck-prs.md +++ b/.docs/research-adf-fleet-allowlist-and-stuck-prs.md @@ -1,6 +1,6 @@ # Research Document: ADF auto-merge allowlist bug and 10 stuck fleet PRs -**Status**: Draft — reviewed 2026-07-01 after deploy-source evidence conflict +**Status**: Draft — Step 1 provenance proved 2026-07-02 **Author**: session agent (Claude Code) **Date**: 2026-07-01 **Reviewers**: Alex Mikhalev @@ -11,13 +11,12 @@ The ADF auto-merge author-allowlist bug has three layers, not one: 1. **Root cause**: `author_is_agent()` in the orchestrator only recognised `claude-code`, `root`, and `adf-*`-prefixed logins, rejecting six real fleet agents. -2. **Deploy-source question**: Evidence is conflicting. Project instructions - say the orchestrator binary is built from `terraphim-agents`, while - bigbox's `~/.zsh_history` shows real `terraphim-ai` task-branch builds of - `adf`. Neither evidence source alone proves which checkout produced the - currently-installed `/usr/local/bin/adf` because no candidate build has yet - been hash-matched to the installed binary. Therefore **repo identity remains - a blocking provenance question**, not a settled fact. +2. **Deploy-source question**: Step 1 provenance is now proved. The installed + `/usr/local/bin/adf` SHA-256 exactly matches + `/home/alex/projects/terraphim/terraphim-agents/target/release/deps/adf-b7d747a1c218d613`. + The matching artefact was built from `terraphim-agents` main at commit + `0a093aa1803fdbec2f145c430f94fd6310848f40`. Therefore the surviving fix must + land in **terraphim-agents**, not only in terraphim-ai. 3. **Remaining work**: 10 PRs are still stuck. One (`terraphim-clients#31`) was merged in this session. The other 9 fail CI for at least three independent reasons (orchestrator-gate/provider issue, CI-runner rustup proxy bug, @@ -77,16 +76,16 @@ sites: `pr_review::evaluate()` (used in `auto_merge_impl.rs`'s | Component | Location | Purpose | |-----------|----------|---------| -| Allowlist policy candidate A | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | PR #3065 implements a KG-driven allowlist; bigbox history shows at least one `adf` build from this repo. **Gap found during review:** its current KG synonyms list only `implementation-swarm`, not all six blocked fleet logins. | -| Allowlist policy candidate B | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Project deployment instructions say this is the orchestrator binary source; materially ahead in some areas (`blocker_kind`, `max_remediation_attempts`, `From<&AutoMergeConfig>`) | -| Competing fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open; should not be closed until binary provenance proves this repo is not the deploy source | -| Competing fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open; same provenance gate as #70 | +| Allowlist policy candidate A | `terraphim-ai` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | PR #3065 implements a KG-driven allowlist, but **does not target the proven deployed source**. It can still inform the design if its KG approach is ported. Gap found during review: its current KG synonyms list only `implementation-swarm`, not all six blocked fleet logins. | +| Allowlist policy candidate B (**proven deploy source**) | `terraphim-agents` repo, `crates/terraphim_orchestrator/src/pr_review.rs` | Installed binary hash matches a build artefact from this repo. Commit `0a093aa` contains the hardcoded `author_is_agent()` policy and `blocker_kind` logging observed in production. | +| Candidate fix #1 | `terraphim-agents#70` "Fix terraphim-ai#3024: source auto-merge agent-author allowlist from fleet config" | Open; now the primary candidate because it targets the proven deploy source. Must be reviewed for six-login coverage and interaction with #69. | +| Candidate fix #2 | `terraphim-agents#69` "Fix terraphim-ai#3028: include allowlist hint in auto-merge author-rejection" | Open; likely companion/supplement to #70. Must be reviewed before choosing final merge path. | | Issue tracking | `terraphim-ai#3024`, `terraphim-ai#3028` | Filed 2026-06-29 by ADF itself, ~48h before ADF's own remediation agent produced #70/#69; #3024's body records that an *earlier* attempted fix (commit `38f06db0` on a branch that no longer exists) was silently lost | -| Orchestrator config (bigbox) | `/opt/ai-dark-factory/orchestrator.toml` + `conf.d/*.toml` | `max_diff_loc = 10000` matches behaviour seen in the deployed binary, but does not by itself identify the source checkout | +| Orchestrator config (bigbox) | `/opt/ai-dark-factory/orchestrator.toml` + `conf.d/*.toml` | Service working directory is `/opt/ai-dark-factory`; service executes `/usr/local/bin/adf orchestrator.toml`. | ### Data Flow -Orchestrator binary (`/usr/local/bin/adf`, source checkout still to be proven by -hash/build metadata) polls each configured project's Gitea PRs every +Orchestrator binary (`/usr/local/bin/adf`, proven built from `terraphim-agents` +main commit `0a093aa`) polls each configured project's Gitea PRs every reconcile tick → `evaluate_pr_gates`/`evaluate` → rejects any PR whose author isn't in the 3-entry hardcoded allowlist → re-logs the same rejection indefinitely, no backoff. @@ -106,10 +105,9 @@ allowlist? - `pr_review.rs` module has an explicit "zero I/O" contract (see its top-of-file doc comment) — any KG/file-based allowlist loading must live in a separate module (respected in PR #3065 via `agent_allowlist_kg.rs`). -- The deploy-source evidence conflicts: project instructions name - `terraphim-agents`, while bigbox shell history shows `terraphim-ai` - task-branch builds. A safe deploy must first identify or reproduce the exact - binary provenance, then build from the agreed canonical repo. +- The deploy-source evidence is now resolved by hash provenance: deploy work + must use `terraphim-agents` unless a deliberate architecture decision moves + ownership elsewhere. ### Business Constraints - North Star: ADF stabilisation target was 2026-06-15; it's now 2026-07-01, @@ -128,7 +126,7 @@ for 6 of the fleet's most active agents. | Constraint | Why It's Vital | Evidence | |------------|----------------|----------| -| Fix must land in the repo proven to build `/usr/local/bin/adf` and then be deployed | A merged fix in a non-deployed repo has zero production effect | Evidence currently conflicts; hash-level provenance is required | +| Fix must land in `terraphim-agents` and then be deployed | A merged fix in a non-deployed repo has zero production effect | Installed binary hash matches `terraphim-agents` artefact `target/release/deps/adf-b7d747a1c218d613` | | Must not duplicate ADF's own in-flight remediation | Three independent fixes for one bug (agents#70, agents#69, ai#3065) is worse than one, and merging more than one risks conflicting `AutoMergeCriteria` shapes | agents#70/#69 predate this session's fix by 2 days; #3065 uses a different KG-driven design | | Surviving allowlist fix must cover all six blocked fleet logins | Covering only `implementation-swarm` leaves five known fleet agents blocked | terraphim-ai#3024 impact table lists `implementation-swarm`, `odilo-developer`, `meta-coordinator`, `quality-coordinator`, `security-sentinel`, `test-guardian` | @@ -144,9 +142,9 @@ for 6 of the fleet's most active agents. ### Internal Dependencies | Dependency | Impact | Risk | |------------|--------|------| -| terraphim-ai repo's orchestrator copy | Candidate deploy source: bigbox zsh history shows `adf` builds from this repo | High until hash provenance is established | -| terraphim-agents repo's orchestrator copy | Candidate deploy source: project deployment instructions say this builds the orchestrator binary | High until hash provenance is established | -| ADF's own remediation agent (produced #70/#69) | Already attempted this exact fix with a different design | Medium — must not close or merge until provenance decides which repo is canonical | +| terraphim-ai repo's orchestrator copy | Non-deployed reference/duplicate for this incident; PR #3065 can inform design but will not fix production alone | Medium — keeping divergent fixes open creates confusion | +| terraphim-agents repo's orchestrator copy | Proven deploy source for `/usr/local/bin/adf` | High — fix must land here to affect production | +| ADF's own remediation agent (produced #70/#69) | Already attempted this exact fix in the proven deploy source | Medium — must review and merge/adjust rather than duplicate blindly | | `terraphim-gitea-runner` CI infrastructure | One observed failure (`unknown proxy name: 'rustup-with-perms'`) is a runner-host bug, not a code bug | Medium — unknown how many other "failing" PRs are runner flakes vs real breakage | ## Risks and Unknowns @@ -154,43 +152,43 @@ for 6 of the fleet's most active agents. ### Known Risks | Risk | Likelihood | Impact | Mitigation | |------|------------|--------|----------| -| Plan chooses the wrong repo because it trusts shell history or AGENTS.md alone | Medium | High (fix has no production effect) | Reproduce or hash-match the installed binary before merging/closing any competing fix PR | +| Plan chooses the wrong repo because it trusts shell history or AGENTS.md alone | Low after Step 1 | High (fix has no production effect) | Resolved by exact hash match to `terraphim-agents` artefact; preserve evidence in this document | | Surviving fix only allowlists `implementation-swarm` and leaves five known fleet agents blocked | Medium | High (incident partially persists) | Candidate-fix acceptance gate must verify all six fleet logins clear `author_is_agent` | | The current bigbox binary was built from an unmerged task branch; merging a fix to main without accounting for off-main deployed changes regresses production behaviour | Medium | Medium-high | Diff current deployed source branch against main before deploying from main | | terraphim-agents#70/#69 or terraphim-ai#3065 are left open after canonical fix lands, creating future conflicting `AutoMergeCriteria` shapes | Medium | Low-medium (rework, not breakage) | Close superseded PRs only after canonical repo and surviving design are decided | | Blind-merging the other 9 PRs once CI is "green" ships unrelated regressions | Low if this document's guidance is followed | High | Never merge on `mergeable=true` alone; require green combined CI status, verified per PR | ### Open Questions -1. Which repo/branch actually produced the currently-installed `/usr/local/bin/adf`, proven by matching binary hash, build-id, or deployment artefact path? -2. If the source is a task branch, what commits are deployed off-main and must be preserved before redeploying from main? -3. Is `terraphim-agents` supposed to be a live fork of `terraphim_orchestrator`, or is this itself the architectural bug (an accidental duplication from the polyrepo split that should be collapsed back to one source)? -4. Are terraphim-agents#70 and #69 mutually exclusive or stackable (i.e. does #69 depend on #70's allowlist-source refactor)? +1. Are terraphim-agents#70 and #69 mutually exclusive or stackable (i.e. does #69 depend on #70's allowlist-source refactor)? +2. Does #70's fleet-config-sourced allowlist cover all six known blocked logins in the deployed `/opt/ai-dark-factory/conf.d/*.toml` agent set? +3. Should #3065's KG-driven design be ported to `terraphim-agents`, or is #70's fleet-config design preferable because `conf.d` already defines fleet agents? +4. Is `terraphim-ai`'s `terraphim_orchestrator` copy still needed, or should this duplicate be removed/retired after the incident? 5. Was the `38f06db0` "lost commit" mentioned in issue #3024 ever real, or is that itself a symptom of a broken ADF remediation-tracking mechanism worth its own investigation? ### Assumptions Explicitly Stated | Assumption | Basis | Risk if Wrong | Verified? | |------------|-------|---------------|-----------| -| terraphim-ai may be the deploy source for `/usr/local/bin/adf` | Bigbox `~/.zsh_history` shows literal `cargo build -p terraphim_orchestrator --release --bin adf` executed inside a terraphim-ai task-branch checkout | If wrong, effort goes toward the wrong repo | No — direct build history exists, but installed-binary hash provenance is not yet proved | -| terraphim-agents may be the deploy source for `/usr/local/bin/adf` | Project deployment instructions state the orchestrator binary is built from terraphim-agents | If wrong, agents#70/#69 target a non-deployed copy | No — documented policy exists, but installed-binary hash provenance is not yet proved | +| terraphim-agents is the deploy source for `/usr/local/bin/adf` | Installed binary SHA-256 matches `/home/alex/projects/terraphim/terraphim-agents/target/release/deps/adf-b7d747a1c218d613`; matching repo was on main commit `0a093aa` before the artefact build | If wrong, effort goes toward wrong repo | **Yes — exact hash match** | | The 9 CI failures are independent, not systemic | Spot-checked 4 of 9 job logs, found 3 different causes (allowlist-adjacent ADF-gate failures, a runner rustup bug, a genuine clippy lint) | If wrong, a shared fix could unblock more PRs at once than this document assumes | Partially — 4/9 checked | ## Research Findings ### Key Insights -1. This bug already has an ADF-native paper trail (issues + two competing +1. Binary provenance is resolved: `/usr/local/bin/adf` matches a + `terraphim-agents` release artefact, not any current `terraphim-ai` build. +2. This bug already has an ADF-native paper trail (issues + two competing fix PRs) that predates this session's independent discovery — the session should reconcile with, not duplicate, that work. -2. PR #3065's KG-driven design is operationally attractive, but its current +3. PR #3065's KG-driven design is operationally attractive, but its current default `recognised_agents.md` is incomplete for #3024: it lists `implementation-swarm` but not `odilo-developer`, `meta-coordinator`, `quality-coordinator`, `security-sentinel`, or `test-guardian`. -3. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with +4. `crates/terraphim_orchestrator` is duplicated across two Gitea repos with diverging implementations. This is now part of the incident, not merely a follow-up, because the competing fixes are in different copies. -4. The deployed binary on bigbox may have been built from a task branch, not - from `main`. This means other changes (e.g. `max_diff_loc: 10_000`, - `blocker_kind` classification) may be silently live in production without - having landed on the branch selected for redeploy. +5. The deployed binary was built from `terraphim-agents` main commit `0a093aa`. + Current `target/release/adf` was rebuilt later and no longer matches, but the + exact matching artefact still exists in `target/release/deps/`. 5. CI failures on the 9 non-#31 stuck PRs are **not** one problem: at least one ADF-gate-only failure pattern (adf/pr-reviewer, adf/validation — plausibly downstream of the Anthropic provider outage found earlier this @@ -223,48 +221,47 @@ for 6 of the fleet's most active agents. ### Technical Spikes Needed | Spike | Purpose | Estimated Effort | |-------|---------|-------------------| -| Prove the exact repo/branch that built the current bigbox binary | Avoid landing/deploying a fix in the wrong repo; know what else is silently deployed off-main | 30–60 min (hash-match installed binary against candidate builds, inspect deployment scripts/history) | | Verify candidate allowlist coverage for all six fleet logins | Ensure the chosen fix actually closes #3024 rather than only unblocking `implementation-swarm` | 10–15 min | +| Review #70 and #69 together | Decide whether #70 alone, #69 alone, both stacked, or a KG-design port is the surviving `terraphim-agents` fix | 15–30 min | | Job-log drill-down for remaining unattributed PRs | Complete the CI failure taxonomy before any merge attempt | 30–45 min | | Diff full terraphim-ai vs terraphim-agents `terraphim_orchestrator` trees | Quantify total divergence, scope a reconciliation | 1–2 hours, separate task | ## Recommendations ### Proceed/No-Proceed -Proceed to design, but keep repo identity as the first blocking gate. The -design's focus is: -1. Prove which repo/branch produced the installed binary and choose the - surviving fix accordingly. +Proceed to design with repo identity resolved: **terraphim-agents is canonical +for the deployed `adf` binary**. The design's focus is: +1. Choose between #70/#69 and a port of #3065's KG-driven design. 2. Verify the surviving fix covers all six known fleet agent logins. -3. Finish CI failure attribution for the 9 remaining stuck PRs. -4. Apply a mechanical merge/fix/close decision rule. +3. Deploy from `terraphim-agents` main with rollback. +4. Finish CI failure attribution for the 9 remaining stuck PRs. +5. Apply a mechanical merge/fix/close decision rule. ### Scope Recommendations -- Design phase should produce: (a) a binary-provenance gate, (b) a branch plan - for either #3065 or agents#70/#69 depending on that gate, (c) a per-PR - remediation plan for the 9 CI-failing PRs *only after* their failure causes - are fully attributed. +- Design phase should produce: (a) a `terraphim-agents` fix selection plan, + (b) an all-six-login acceptance gate, (c) a deploy/rollback plan, (d) a + per-PR remediation plan for the 9 CI-failing PRs *only after* their failure + causes are fully attributed. - Do not expand scope to the terraphim-ai/terraphim-agents duplication itself in this pass — flag it as a follow-up architecture issue. ### Risk Mitigation Recommendations -- Do not merge #3065 or close agents#70/#69 until the binary provenance gate - is complete. -- After merging the chosen fix, explicitly build from the selected canonical - branch and deploy to bigbox; do not assume merging is enough. +- Do not merge #3065 as production remediation; it targets the non-deployed + duplicate for this incident. +- Do not close #3065 until the `terraphim-agents` surviving fix is merged and + deployed, because its KG approach may still be useful as design input. +- After merging the chosen `terraphim-agents` fix, explicitly build from + `terraphim-agents` main and deploy to bigbox; do not assume merging is enough. - Do not merge any of the 9 remaining PRs until each has a filled-in taxonomy row and passes the Decision Rule. ## Next Steps If approved: -1. **Binary-provenance spike** (30–60 min): prove which repo/branch built the - current bigbox `/usr/local/bin/adf` by hash-matching or deployment artefact - trace, and record off-main commits if any. -2. **Choose one fix and verify coverage**: if `terraphim-ai` is proven - canonical, use #3065 only after adding/verifying all six fleet logins; if - `terraphim-agents` is proven canonical, review #70/#69 and either merge them - or port #3065's KG design there with the same six-login coverage. +1. **Review #70/#69 and #3065's design**: select the surviving + `terraphim-agents` fix path. +2. **Verify coverage**: ensure the selected fix recognises all six fleet logins + and still rejects unknown human/bot logins. 3. **Deploy the chosen fix** (owner's call on deploy timing): build from the selected canonical branch, copy to `/usr/local/bin/adf`, restart `adf-orchestrator`. From 92c2f8282b8f43f7537320c0ebbd3e1da6eafd74 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 6 Jul 2026 09:02:38 +0100 Subject: [PATCH 6/7] docs(agents): add AI onboarding quickstart --- README.md | 6 +- docs/src/SUMMARY.md | 1 + .../howto/ai-agent-onboarding-quickstart.md | 150 ++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 docs/src/howto/ai-agent-onboarding-quickstart.md diff --git a/README.md b/README.md index 83a0ab61a..96572ce8d 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ cargo install terraphim-cli # Automation CLI (8 commands) - ⚡ Lightweight (15 MB RAM, 13 MB disk) - 🚀 Fast (<200ms operations) -**Learn more**: [Quickstart](QUICKSTART.md) | [Changelog](https://docs.terraphim.ai/src/changelog.html) | [Cross-Platform Guide](docs/archive/root/CROSS_PLATFORM_STATUS.md) +**Learn more**: [Quickstart](QUICKSTART.md) | [AI Agent Onboarding](docs/src/howto/ai-agent-onboarding-quickstart.md) | [Changelog](https://docs.terraphim.ai/src/changelog.html) | [Cross-Platform Guide](docs/archive/root/CROSS_PLATFORM_STATUS.md) You can use it as a local search engine, configured to search for different types of content on StackOverflow, GitHub, and the local filesystem using a predefined folder, which includes your Markdown files. @@ -183,6 +183,10 @@ pip install terraphim-automata (See the [desktop README](desktop/README.md), [TUI documentation](docs/tui-usage.md), and [development setup guide](docs/src/development-setup.md) for more details.) +### AI Agent Onboarding + +AI coding agents should start with the [AI Agent Onboarding Quickstart](docs/src/howto/ai-agent-onboarding-quickstart.md). It covers repository orientation, Terraphim-first search, Gitea task tracking, quality gates, release checks, and safe handoff expectations for work in this repository. + ## 📚 Usage Examples ### 🦀 Rust CLI/TUI diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 9518b0ef5..f5dd32425 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -36,6 +36,7 @@ ## How-Tos +- [AI Agent Onboarding Quickstart](./howto/ai-agent-onboarding-quickstart.md) - [Learning Capture for Claude Code](./howto/learning-capture-claude-code.md) - [Learning Capture for opencode](./howto/learning-capture-opencode.md) - [Personal Assistant Role (JMAP + Obsidian)](./howto/personal-assistant-role.md) diff --git a/docs/src/howto/ai-agent-onboarding-quickstart.md b/docs/src/howto/ai-agent-onboarding-quickstart.md new file mode 100644 index 000000000..f716a156b --- /dev/null +++ b/docs/src/howto/ai-agent-onboarding-quickstart.md @@ -0,0 +1,150 @@ +# AI Agent Onboarding Quickstart + +This quickstart is for AI coding agents working in `github.com/terraphim/terraphim-ai`. It describes the minimum safe workflow for becoming useful quickly without losing context, duplicating work, or bypassing project quality gates. + +## First five minutes + +1. Confirm where you are working. + + ```bash + pwd + git status --short + git branch --show-current + ``` + +2. Read the repository instructions before changing code. + + ```bash + git ls-files 'AGENTS.md' 'CLAUDE.md' '.docs/summary.md' 'docs/src/howto/ai-agent-onboarding-quickstart.md' + ``` + +3. Check whether the work is already in progress. + + ```bash + git fetch origin + git branch -r + gtr list-pulls --owner terraphim --repo terraphim-ai --state open + ``` + +4. Inspect existing tasks before creating new ones. + + ```bash + gtr ready --owner terraphim --repo terraphim-ai + gtr triage --owner terraphim --repo terraphim-ai + ``` + +5. Search the codebase with Terraphim tools first. + + ```bash + terraphim-grep "symbol or behaviour" --haystack code + terraphim-grep "symbol or behaviour" --haystack code -C 3 + ``` + +## Working rules + +- Treat Gitea as the source of truth for task tracking. +- Claim or update the relevant issue before substantial implementation work. +- Prefer the smallest correct change. +- Do not revert user or other-agent changes unless explicitly asked. +- Use `terraphim-grep` for content search before falling back to lower-level tools. +- Use `gtr` for issue and pull request operations. +- Keep secrets out of the repository; use 1Password injection or existing secrets configuration. +- Do not overwrite `.env` files. +- Do not use mocks in tests. +- Keep local, GitHub, and Gitea state aligned when publishing changes. + +## Common commands + +### Search + +```bash +terraphim-grep "DeviceStorage::init" --haystack code -C 3 +terraphim-grep "session persistence" --paths . --thesaurus .terraphim/thesaurus.json -n 8 -C 2 +``` + +Use file-name lookup only when you are looking for paths rather than content: + +```bash +git ls-files '*orchestrator*.rs' +fd 'config.toml' crates/ +``` + +### Task management + +```bash +gtr ready --owner terraphim --repo terraphim-ai +gtr view-issue --owner terraphim --repo terraphim-ai --index ISSUE_NUMBER +gtr comment --owner terraphim --repo terraphim-ai --index ISSUE_NUMBER --body "Progress update" +gtr list-pulls --owner terraphim --repo terraphim-ai --state open +``` + +### Rust backend + +```bash +cargo fmt --check +cargo test --workspace +cargo clippy --workspace --all-targets -- -D warnings +``` + +For focused work, prefer package-scoped commands: + +```bash +cargo test -p terraphim_service +cargo clippy -p terraphim_agent --all-targets -- -D warnings +``` + +### Frontend + +```bash +cd desktop +bun install +bun run check +bun test +``` + +## Update and release checks + +Terraphim client binaries are released from `terraphim/terraphim-clients`. Autoupdate validation should check both binaries: + +```bash +terraphim-grep --version +terraphim-grep check-update +terraphim-grep update + +terraphim-agent --version +terraphim-agent check-update +terraphim-agent update +``` + +Release archives used by autoupdate must be embedded-signed with zipsign. If update verification fails with `could not find read signatures in .tar.gz file`, the published archive is unsigned and the release pipeline must sign tar archives before upload. + +## Quality gate before handoff + +Before reporting completion, collect evidence rather than relying on intent: + +```bash +git status --short +cargo fmt --check +cargo test -p CHANGED_PACKAGE +cargo clippy -p CHANGED_PACKAGE --all-targets -- -D warnings +``` + +For changed files, run the bug scanner where available: + +```bash +ubs $(git diff --name-only --cached) +``` + +If code changed, check coverage with the most focused feasible command, for example: + +```bash +cargo llvm-cov -p CHANGED_PACKAGE --summary-only +``` + +## Handoff checklist + +- Summarise what changed and why. +- List tests, linters, coverage, and release checks that ran. +- State any blocked work or follow-up issues. +- Update the Gitea issue or pull request with the same evidence. +- Leave unrelated working tree changes untouched. From 58ad9745b97b5d7a04b36050c2e836a9eabbc62d Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 6 Jul 2026 10:56:30 +0100 Subject: [PATCH 7/7] fix(orchestrator): update allowlist hint test --- crates/terraphim_orchestrator/src/pr_poller.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/terraphim_orchestrator/src/pr_poller.rs b/crates/terraphim_orchestrator/src/pr_poller.rs index 5ae575325..92045b6ef 100644 --- a/crates/terraphim_orchestrator/src/pr_poller.rs +++ b/crates/terraphim_orchestrator/src/pr_poller.rs @@ -324,7 +324,10 @@ pub fn evaluate_pr_gates( && !author_is_agent(&pr.author_login, &criteria.recognised_agent_logins) { return EvaluationOutcome::HumanReviewNeeded { - reason: agent_author_rejection_reason(&pr.author_login, &criteria.recognised_agent_logins), + reason: agent_author_rejection_reason( + &pr.author_login, + &criteria.recognised_agent_logins, + ), }; } if pr.diff_loc > criteria.max_diff_loc { @@ -727,8 +730,8 @@ mod tests { "reason must mention allowlisting, got: {reason}" ); assert!( - reason.contains("orchestrator.toml"), - "reason must point to the fleet config file, got: {reason}" + reason.contains("kg/recognised_agents.md"), + "reason must point to the KG allowlist file, got: {reason}" ); }