Merge branch 'main' into copilot/fix-squash-merge-failure
This commit is contained in:
commit
95bd7ba8aa
3 changed files with 102 additions and 2 deletions
|
|
@ -637,8 +637,12 @@ function buildParams(
|
|||
options?: AnthropicOptions,
|
||||
): MessageCreateParamsStreaming {
|
||||
const { cacheControl } = getCacheControl(model.baseUrl, options?.cacheRetention);
|
||||
// For OAuth (Claude Max/Pro), strip variant suffixes like [1m] from model ID.
|
||||
// The API only accepts the base model ID (e.g. "claude-opus-4-6"),
|
||||
// not internal variant identifiers (e.g. "claude-opus-4-6[1m]").
|
||||
const apiModelId = isOAuthToken ? model.id.replace(/\[.*\]$/, "") : model.id;
|
||||
const params: MessageCreateParamsStreaming = {
|
||||
model: model.id,
|
||||
model: apiModelId,
|
||||
messages: convertMessages(context.messages, model, isOAuthToken, cacheControl),
|
||||
max_tokens: options?.maxTokens || (model.maxTokens / 3) | 0,
|
||||
stream: true,
|
||||
|
|
|
|||
|
|
@ -3065,7 +3065,11 @@ export function verifyExpectedArtifact(unitType: string, unitId: string, base: s
|
|||
}
|
||||
}
|
||||
|
||||
// complete-slice must also produce a UAT file
|
||||
// complete-slice must also produce a UAT file AND mark the slice [x] in the roadmap.
|
||||
// Without the roadmap check, a crash after writing SUMMARY+UAT but before updating
|
||||
// the roadmap causes an infinite skip loop: the idempotency key says "done" but the
|
||||
// state machine keeps returning the same complete-slice unit (roadmap still shows
|
||||
// the slice incomplete), so dispatchNextUnit recurses forever.
|
||||
if (unitType === "complete-slice") {
|
||||
const parts = unitId.split("/");
|
||||
const mid = parts[0];
|
||||
|
|
@ -3076,6 +3080,17 @@ export function verifyExpectedArtifact(unitType: string, unitId: string, base: s
|
|||
const uatPath = join(dir, buildSliceFileName(sid, "UAT"));
|
||||
if (!existsSync(uatPath)) return false;
|
||||
}
|
||||
// Verify the roadmap has the slice marked [x]. If not, the completion
|
||||
// record is stale — the unit must re-run to update the roadmap.
|
||||
const roadmapFile = resolveMilestoneFile(base, mid, "ROADMAP");
|
||||
if (roadmapFile && existsSync(roadmapFile)) {
|
||||
try {
|
||||
const roadmapContent = readFileSync(roadmapFile, "utf-8");
|
||||
const roadmap = parseRoadmap(roadmapContent);
|
||||
const slice = roadmap.slices.find(s => s.id === sid);
|
||||
if (slice && !slice.done) return false;
|
||||
} catch { /* corrupt roadmap — be lenient and treat as verified */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -409,6 +409,87 @@ function createGitBase(): string {
|
|||
}
|
||||
}
|
||||
|
||||
// ═══ verifyExpectedArtifact: complete-slice roadmap check ════════════════════
|
||||
// Regression for #indefinite-hang: complete-slice must verify roadmap [x] or
|
||||
// the idempotency skip loops forever after a crash that wrote SUMMARY+UAT but
|
||||
// did not mark the roadmap done.
|
||||
|
||||
const ROADMAP_INCOMPLETE = `# M001: Test Milestone
|
||||
|
||||
## Slices
|
||||
|
||||
- [ ] **S01: Test Slice** \`risk:low\`
|
||||
> After this: something works
|
||||
`;
|
||||
|
||||
const ROADMAP_COMPLETE = `# M001: Test Milestone
|
||||
|
||||
## Slices
|
||||
|
||||
- [x] **S01: Test Slice** \`risk:low\`
|
||||
> After this: something works
|
||||
`;
|
||||
|
||||
{
|
||||
console.log("\n=== verifyExpectedArtifact: complete-slice — all artifacts present + roadmap marked [x] returns true ===");
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
||||
writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# Summary\n", "utf-8");
|
||||
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
||||
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
|
||||
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
||||
assert(result === true, "SUMMARY + UAT + roadmap [x] should verify as true");
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY + UAT present but roadmap NOT marked [x] returns false ===");
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
||||
writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# Summary\n", "utf-8");
|
||||
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
||||
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_INCOMPLETE, "utf-8");
|
||||
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
||||
assert(result === false, "roadmap not marked [x] should return false (crash recovery scenario)");
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY present but UAT missing returns false ===");
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
||||
writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# Summary\n", "utf-8");
|
||||
// no UAT file
|
||||
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
|
||||
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
||||
assert(result === false, "missing UAT should return false");
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
console.log("\n=== verifyExpectedArtifact: complete-slice — no roadmap file present is lenient (returns true) ===");
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
||||
writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# Summary\n", "utf-8");
|
||||
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
||||
// no roadmap file
|
||||
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
||||
assert(result === true, "missing roadmap file should be lenient and return true");
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
}
|
||||
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
// Results
|
||||
// ═════════════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue