mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-19 10:04:16 +00:00
Merge terminal replay card fix
Owner-authorized dev follow-up for stale Finalizing cards. Full CI and review continue.
This commit is contained in:
commit
87cac11408
2 changed files with 42 additions and 0 deletions
|
|
@ -2583,8 +2583,12 @@ export function createChatInstance({
|
|||
}
|
||||
for (const msg of messages) learnSubagentLineage(msg);
|
||||
|
||||
const historicalTerminalProjections = new Set();
|
||||
for (const msg of messages) if (msg.historical_terminal && msg.task_id) {
|
||||
historicalTerminals.set(msg.task_id, msg.historical_terminal);
|
||||
if (msg.summary_kind === 'terminal_root_projection' || msg.outcome_final === true) {
|
||||
historicalTerminalProjections.add(msg.task_id);
|
||||
}
|
||||
}
|
||||
// First pass builds card state without DOM insertion.
|
||||
_syncPass1Active = true;
|
||||
|
|
@ -2779,6 +2783,26 @@ export function createChatInstance({
|
|||
}
|
||||
_historyRow = null;
|
||||
|
||||
// A terminal-root projection is the durable result authority,
|
||||
// even though it is an intentionally hidden history row. Do
|
||||
// not let a later authored_root_summary (which may still say
|
||||
// `finalizing`) leave the card open after restart. Resolve it
|
||||
// only after replay has seen all narrative rows so the
|
||||
// terminal fact cannot itself be downgraded by later prose.
|
||||
for (const [tid, historicalTerminal] of historicalTerminals) {
|
||||
if (!historicalTerminalProjections.has(tid)) continue;
|
||||
const terminalRecord = { ...historicalTerminal, task_id: tid };
|
||||
if (!taskDoneIsTerminal(terminalRecord)) continue;
|
||||
if (subagentChildParents.has(tid)) {
|
||||
routeSubagentTerminalToCard(tid, terminalRecord);
|
||||
continue;
|
||||
}
|
||||
const rec = liveCardRecords.get(tid);
|
||||
if (!rec) continue;
|
||||
insertCardIfNeeded(tid);
|
||||
finishLiveCard(tid, taskTerminalPhase(terminalRecord));
|
||||
}
|
||||
|
||||
// Append disconnected visible cards after mid-task reload; skip trivial placeholders.
|
||||
for (const [tid, rec] of liveCardRecords) {
|
||||
reorderDirtyCardIfNeeded(rec);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,24 @@ test(' retained cancelled fact outranks untyped historical answer after result q
|
|||
assert.equal(fx.card('past').querySelector('[data-live-phase]').textContent, 'Cancelled');
|
||||
} finally {fx.instance.destroy(); restoreDom(fx.prior);}
|
||||
});
|
||||
|
||||
test('terminal-root history projection settles a card after a later finalizing summary', async () => {
|
||||
const terminal = {status: 'completed', phase: 'done', ts: '2026-09-09T09:02:00Z',
|
||||
provenance: 'canonical_task_result_after_finalization'};
|
||||
const fx = makeInstance([
|
||||
{task_id: 'replayed', is_progress: true, text: 'Working', ts: '2026-09-09T09:00:00Z'},
|
||||
{task_id: 'replayed', summary_kind: 'terminal_root_projection', historical_terminal: terminal,
|
||||
role: 'system', system_type: 'task_summary', outcome_final: true, ts: '2026-09-09T09:02:00Z'},
|
||||
{task_id: 'replayed', summary_kind: 'authored_root_summary', role: 'system',
|
||||
system_type: 'task_summary', task_phase: 'finalizing', outcome_final: false,
|
||||
status: 'completed', ts: '2026-09-09T09:03:00Z'},
|
||||
]);
|
||||
try {
|
||||
await fx.instance.refreshHistory({revision: 1});
|
||||
assert.equal(fx.card('replayed').dataset.finished, '1');
|
||||
assert.equal(fx.card('replayed').querySelector('[data-live-phase]').textContent, 'Done');
|
||||
} finally { fx.instance.destroy(); restoreDom(fx.prior); }
|
||||
});
|
||||
for (const via of ['log', 'detail']) test(`child terminal ${via} retains the producer model observation`, async () => {
|
||||
const observation = {source: 'usable_solve_response', used_model: 'fallback', requested_model: 'initial',
|
||||
used_local: false, requested_use_local: false, llm_call_id: 'call', provider: 'openrouter'};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue