fix(ai): JSONL fallback returns 'failed' on partial-insert (was 'applied')
Previous version reported `status: 'applied'` whenever at least one root landed, with a partial-failure note in `message`. But the orchestrator's retry / minimal-skills / batch_design-fallback chain checks `status === 'applied'` to decide whether to bypass retry — a partial insert (e.g. 1/5 roots landed because `defaultParentId` was stale) would short-circuit retry and leave the user with a degraded design that the system never tried to fix. Now any failed root flips the dispatch to `status: 'failed'` so the orchestrator's retry path can take over. The successful partial inserts are still surfaced in `insertedNodes` so the surrounding history-batch wrapper can roll them back / clean up — `failed` with non-empty `insertedNodes` is a legitimate combination meaning "side effects happened but the dispatch did not complete its contract". Three outcomes now: - All N roots land → `applied` with full count. - 1..N-1 land → `failed` with partial-success `insertedNodes` and a message naming the parent id + failed root ids. - 0 land → `failed` with empty `insertedNodes` and the same diagnostic.
This commit is contained in:
parent
f6bc47b347
commit
4043e9915f
|
|
@ -501,25 +501,47 @@ function applyBatchDesignAsJsonl(jsonl: string, ctx: DispatchContext): DispatchR
|
|||
failedIds.push(root.id);
|
||||
}
|
||||
}
|
||||
if (inserted.length === 0) {
|
||||
// Any failure to land a root is a hard failure — even a single missing
|
||||
// root usually means the defaultParentId is stale, the model emitted a
|
||||
// dangling _parent reference, or the doc state has drifted. Reporting
|
||||
// `applied` for partial inserts would lie to the orchestrator: it
|
||||
// checks `status === 'applied'` to decide whether to skip retry, so a
|
||||
// partial would silently degrade the design without ever exercising
|
||||
// the orchestrator's retry / minimal-skills / batch_design fallback
|
||||
// chain. We still surface the partial-success roots in `insertedNodes`
|
||||
// so the caller can clean them up (or roll back through the history
|
||||
// batch wrapper) instead of leaving orphans.
|
||||
if (failedIds.length > 0) {
|
||||
const failedList = `${failedIds.slice(0, 4).join(', ')}${failedIds.length > 4 ? '…' : ''}`;
|
||||
if (inserted.length === 0) {
|
||||
return {
|
||||
status: 'failed',
|
||||
route: 'batch-design-dsl',
|
||||
toolName: 'batch_design',
|
||||
message:
|
||||
`batch_design.operations parsed as JSONL (${tree.length} root(s)) but none landed — ` +
|
||||
`parent id '${parentId ?? 'page-root'}' may be stale or unresolved. ` +
|
||||
`Failed root ids: ${failedList}`,
|
||||
insertedNodes: [],
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'failed',
|
||||
route: 'batch-design-dsl',
|
||||
toolName: 'batch_design',
|
||||
message:
|
||||
`batch_design.operations parsed as JSONL (${tree.length} root(s)) but none landed — ` +
|
||||
`parent id '${parentId ?? 'page-root'}' may be stale or unresolved. ` +
|
||||
`Failed root ids: ${failedIds.slice(0, 4).join(', ')}${failedIds.length > 4 ? '…' : ''}`,
|
||||
insertedNodes: [],
|
||||
`batch_design.operations partial failure: ${inserted.length}/${tree.length} root(s) ` +
|
||||
`landed, ${failedIds.length} did not (parent id '${parentId ?? 'page-root'}'). ` +
|
||||
`Failed root ids: ${failedList}`,
|
||||
insertedNodes: inserted,
|
||||
};
|
||||
}
|
||||
const totalLive = countDescendants(inserted);
|
||||
const partial = failedIds.length > 0 ? ` (${failedIds.length} root(s) failed to insert)` : '';
|
||||
return {
|
||||
status: 'applied',
|
||||
route: 'batch-design-dsl',
|
||||
toolName: 'batch_design',
|
||||
message: `Applied batch_design.operations as JSONL (${inserted.length}/${tree.length} root node(s); ${totalLive} total)${partial}.`,
|
||||
message: `Applied batch_design.operations as JSONL (${tree.length} root node(s); ${totalLive} total).`,
|
||||
insertedNodes: inserted,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue