* chore: wire docs/agents config into AGENTS.md Agent skills section
Add the `## Agent skills` discovery block pointing the engineering
skills at the existing docs/agents/{issue-tracker,triage-labels,domain}.md
files (issue tracker, triage label mapping, single-context domain docs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#214): make gsd-phase-researcher survive OpenCode write-tool truncation
OpenCode caps model output at OUTPUT_TOKEN_MAX=32000 and the thinking
budget shares that pool (upstream opencode#18108). A single oversized
`write` tool call for RESEARCH.md is truncated mid-payload, yielding
`JSON Parse error: Expected '}'`, which OpenCode misclassifies and then
doom-loops retrying identically. Short content writes fine; long
content fails 100% (reproducible, OpenCode 1.15.10).
Add a Step 6 write contract to agents/gsd-phase-researcher.md: keep the
single-Write default (no behavior change for Claude Code and other
runtimes that don't truncate), but on a truncation/invalid-tool failure
build the file incrementally via a sentinel-based Write -> Read -> Edit
sequence so no single tool-call payload is large enough to truncate;
never silently fall back to returning content (which truncates
identically). This is the upstream-recommended mitigation (write in
smaller chunks; use edit for follow-on writes).
Locked with a prompt-contract regression test mirroring the bug-222
write-contract pattern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#214): add changeset for OpenCode write-truncation fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
1.9 KiB
JavaScript
62 lines
1.9 KiB
JavaScript
// allow-test-rule: source-text-is-the-product
|
|
'use strict';
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
const RESEARCHER_PATH = path.join(REPO_ROOT, 'agents', 'gsd-phase-researcher.md');
|
|
|
|
function readResearcherPrompt() {
|
|
return fs.readFileSync(RESEARCHER_PATH, 'utf8');
|
|
}
|
|
|
|
describe('bug #214: phase researcher must survive OpenCode write-tool truncation', () => {
|
|
test('Step 6 documents the large-file / truncation fallback write contract', () => {
|
|
const prompt = readResearcherPrompt();
|
|
|
|
assert.match(
|
|
prompt,
|
|
/truncat/i,
|
|
'Step 6 must name the truncation failure mode.'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/incrementa/i,
|
|
'Step 6 must instruct incremental construction on large files.'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/<!-- gsd:write-continue -->/,
|
|
'Step 6 must define the continuation sentinel for incremental writes.'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/do NOT retry the same oversized call/i,
|
|
'Step 6 must forbid identical retry of the oversized write (doom-loop guard).'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/do NOT silently fall back to returning content/i,
|
|
'Step 6 must forbid silent fallback to returning content.'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/`Read` the file, then `Edit`/i,
|
|
'Step 6 must require Read before Edit (OpenCode edit requires a prior Read).'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/no trailing sentinel/i,
|
|
'Step 6 must instruct removing the sentinel on the final section.'
|
|
);
|
|
assert.match(
|
|
prompt,
|
|
/write the whole file in a single `Write` call/i,
|
|
'Step 6 must keep single-Write as the default path (no regression for non-truncating runtimes).'
|
|
);
|
|
});
|
|
});
|