Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion agents/ai-tfa-coordinator.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ description: 'Per-test collaborative-RCA coordinator (autonomous — never promp
- orchestrator: Agent(subagent_type="tfa-rca:ai-tfa-coordinator", prompt="RCA testRunId=39 — error: empty buildName rejected on POST /builds") → drives the loop, returns RCA_OUTPUT
- sibling confirm: Agent(subagent_type="tfa-rca:ai-tfa-coordinator", prompt="RCA testRunId=40 — pre-seed: cause=<rep root cause>, suspect PR=#7421") → one-turn confirm against this test logs
- user: "run collaborative RCA on test run 39" → single-test loop to RESOLVED/PENDING'
tools: [Bash, Read, Grep, Glob, Task, mcp__*__tfaRcaTurn, mcp__*__getTfaTurnResult, mcp__github__*]
model: sonnet
---

Expand Down
43 changes: 43 additions & 0 deletions tests/wiring.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,3 +1153,46 @@ test("SETUP.md gates its remaining steps on the sign-in", () => {
assert.match(flat, /wiring rather than sign-in/u,
"the two failure modes must be distinguished — guessing wastes a round trip");
});

// ---- the coordinator must not carry a tools allowlist ------------------------
//
// It had one, and it was inert for months because the YAML frontmatter failed to parse.
// Fixing the parse ACTIVATED it, and a live run then died: the coordinator was granted
// only `Bash` and `Read`. Three separate faults in one line —
//
// tools: [Bash, Read, Grep, Glob, Task, mcp__*__tfaRcaTurn, mcp__*__getTfaTurnResult, mcp__github__*]
//
// 1. `mcp__*__tfaRcaTurn` did not match the real `mcp__plugin_tfa-rca_bstack__tfaRcaTurn`;
// 2. `Task`/`Grep`/`Glob` were not granted either;
// 3. `ToolSearch` was absent — and MCP tools are DEFERRED, so without it no schema can
// be loaded and `tfaRcaTurn` is unreachable even when its name is allowed.
//
// It had never been exercised, so none of that had ever been caught.
//
// The deeper reason not to fix the list: this plugin routes evidence to whatever tools
// the CUSTOMER has — a log store, a cluster, a metrics surface, a forge. Those are
// unknowable when the file is written, so an allowlist cannot express what a coordinator
// legitimately needs. Inheriting the session's tools is not laxness here, it is the only
// thing consistent with "generic over product and infra".
test("the coordinator agent declares no tools allowlist", () => {
// MUTATION: add any `tools:` line to the frontmatter -> fails.
const src = readFileSync(join(ROOT, "agents/ai-tfa-coordinator.md"), "utf8");
const fm = src.split("---")[1] ?? "";
assert.doesNotMatch(
fm, /^tools:/mu,
"a coordinator restricted to a fixed tool list cannot reach a customer's connectors, " +
"and the last such list silently reduced it to Bash + Read",
);

// The frontmatter must still PARSE — an unparseable block drops every field silently,
// which is how the broken allowlist stayed hidden. Continuation lines of a multi-line
// scalar must be indented; at column 0 a strict parser sees a new document-level
// sequence and discards the lot.
for (const line of fm.split("\n")) {
assert.doesNotMatch(
line, /^- /u,
"a frontmatter continuation line at column 0 makes the whole block unparseable, " +
"and the runtime then drops every field but the filename-derived name",
);
}
});
Loading