fix(research): the contrarian runs as a second wave with the leading answer to attack
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f32baf50ad
commit
b16e39ccd9
5 changed files with 104 additions and 15 deletions
|
|
@ -1199,3 +1199,60 @@ test('[#102] sibling: commands/trekexecute.md names project-dir and repo-root ca
|
|||
assert.doesNotMatch(text, /plugin-root candidates/);
|
||||
assert.equal((text.match(/project-dir and repo-root candidates/g) || []).length, 2);
|
||||
});
|
||||
|
||||
// --- #113: the contrarian gets a conclusion to attack -----------------------
|
||||
// contrarian-researcher was launched in the same parallel message as the agents
|
||||
// whose conclusion it is meant to attack, and standard effort pointed at a
|
||||
// "conditional trigger" that nothing defined. It now runs as wave 2, after wave
|
||||
// 1 returns, given wave 1's leading answer from the external findings only,
|
||||
// with the local parts stripped (the de-localising rule of External agents), so
|
||||
// no local file name or project term reaches its web queries.
|
||||
|
||||
const RESEARCH = 'commands/trekresearch.md';
|
||||
const RESEARCH_ORCH = 'agents/research-orchestrator.md';
|
||||
|
||||
test('[#113] Phase 4 launches contrarian-researcher as wave 2 after wave 1, with the leading answer and claims from external findings only, and names the deep-research case', () => {
|
||||
const text = read(RESEARCH);
|
||||
const ext = partAt(RESEARCH, '### External agents (scope = both or external)', (l) => /^## /.test(l));
|
||||
assert.doesNotMatch(ext, /Launch ALL selected agents \*\*in parallel\*\*/, 'Launch rules still start every selected agent, the contrarian too, in one parallel message');
|
||||
assert.match(ext, /Launch in two waves, both in Phase 4 \(before Phase 4\.5 and Phase 5/);
|
||||
assert.match(ext, /\*\*Wave 1:\*\* ALL selected agents except `contrarian-researcher` \*\*in parallel\*\* in a single message/);
|
||||
assert.match(ext, /\*\*Wave 2:\*\* `contrarian-researcher`, when selected, after wave 1 returns/);
|
||||
assert.match(ext, /the leading answer \(one or two sentences\), the claims for it and the alternatives wave 1 dismissed/);
|
||||
assert.match(ext, /taken from wave 1's external findings only, never from the local agents' findings/, 'wave 2 does not say external findings only');
|
||||
assert.match(ext, /stripped of local parts like the research question above \(absolute paths, user names, internal project or repository names, ticket IDs\)/, 'wave 2 does not apply the stripping rule');
|
||||
assert.match(ext, /Pass the research question to them with the local parts \(absolute paths, user names, internal project or repository names, ticket IDs\) already removed/);
|
||||
assert.match(ext, /With `--engine deep-research` \(`effective_engine = deep-research`\), wave 2 runs after the engine returns, from the leading answer of its report/);
|
||||
const p4 = partAt(RESEARCH, '## Phase 4 — Parallel research (agent swarm)', (l) => /^## /.test(l));
|
||||
assert.match(p4, /then run wave 2 \(`contrarian-researcher`, see Launch rules\) from the report's leading answer/, 'the deep-research step 5 does not hand over to wave 2');
|
||||
const w2 = text.indexOf('**Wave 2:**');
|
||||
assert.ok(w2 > text.indexOf('## Phase 4 —') && w2 < text.indexOf('## Phase 4.5 —'), 'wave 2 is not in Phase 4, before Phase 4.5');
|
||||
});
|
||||
|
||||
test('[#113] no conditional trigger is left, and high effort keeps contrarian-researcher unconditional, as wave 2', () => {
|
||||
const text = flat(read(RESEARCH));
|
||||
assert.doesNotMatch(text, /triggers conditionally when a leading recommendation is emerging/);
|
||||
assert.doesNotMatch(text, /use the existing conditional triggers/);
|
||||
const high = flat(section(read(RESEARCH), '### High-effort behavior (v5.1.1)'));
|
||||
assert.ok(high.includes('force `contrarian-researcher` to always-on: in high-effort mode `contrarian-researcher` runs unconditionally, as wave 2 (see Launch rules), so the final brief always carries an adversarial counter-evidence pass'),
|
||||
'high effort does not keep the contrarian unconditional as wave 2');
|
||||
});
|
||||
|
||||
test('[#113] sibling: README.md', () => {
|
||||
const text = flat(read('README.md'));
|
||||
assert.doesNotMatch(text, /contrarian-researcher when a leading recommendation forms/);
|
||||
assert.ok(text.includes('contrarian-researcher, when selected, runs in wave 2 after the other external agents return, with their leading answer to attack (always at `effort=high`)'),
|
||||
'README.md does not describe wave 2');
|
||||
});
|
||||
|
||||
test('[#113] sibling: agents/research-orchestrator.md', () => {
|
||||
const p2 = flat(section(read(RESEARCH_ORCH), '### Phase 2 — Parallel research'));
|
||||
assert.doesNotMatch(p2, /Launch ALL selected agents \*\*in parallel\*\*/);
|
||||
assert.match(p2, /\*\*Wave 1:\*\* ALL selected agents except `contrarian-researcher` \*\*in parallel\*\* using the Agent tool — one message, multiple tool calls/);
|
||||
assert.match(p2, /\*\*Wave 2:\*\* `contrarian-researcher`, after wave 1 returns/);
|
||||
assert.match(p2, /the leading answer \(one or two sentences\), the claims for it and the alternatives wave 1 dismissed/);
|
||||
assert.match(p2, /taken from wave 1's external findings only, never from the local agents' findings/);
|
||||
assert.match(p2, /with the local parts \(absolute paths, user names, internal project or repository names, ticket IDs\) removed/);
|
||||
assert.ok(flat(read(RESEARCH_ORCH)).includes('| `contrarian-researcher` | Counter-evidence, overlooked alternatives, reasons to reconsider; runs in wave 2, against wave 1\'s leading answer |'),
|
||||
'the agent table does not say the contrarian runs in wave 2');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue