TASK-conversation-console-workflow: preserve drafts after preview invalidation

This commit is contained in:
thePR0M3TH3AN committed 2026-10-01 07:49:05 -04:00
1 parent ffff333f48
commit 0747b35341
4 files changed
+49 -22

No files matched your search

+3 -2
View File
@@ -2572,8 +2572,8 @@ test_integrity_note:
then: "Each original assertion and capture executes against the selected view without changing capture order, viewport coverage, artifact destination, or artifact safeguards"
- id: SCN-console-priority-preview-invalidates-on-newer-evidence
given: "A task priority preview and unsent priority and reason values are created from task evidence revision N"
when: "A separate confirmed sample API action advances that task to authoritative revision N+1 and Console refresh loads the newer evidence"
then: "The revision N token, preview, and confirmation control are absent; revision N+1 is visible, the unsent values remain intact and editable, and only a newly generated preview bound to N+1 can be presented"
when: "A separate confirmed sample API action advances that task to authoritative revision N+1, then the reader refreshes again after navigating away and back"
then: "The revision N token, preview, and confirmation control remain absent; revision N+1 is visible, the unsent values remain intact and editable across both refreshes, and a new preview is bound to N+1"
- id: SCN-console-current-preview-and-draft-survive-unchanged-refresh
given: "A task has an active priority preview and unsent priority and reason values bound to its current evidence revision"
when: "Console refresh returns the same task revision"
@@ -2602,6 +2602,7 @@ test_integrity_note:
- "Selected fragment, visible view, original assertion results, and the unchanged ordered screenshot set"
- "Revision N+1 displayed after refresh, with the old preview token and confirmation control unavailable"
- "Unsent priority and reason values retained and editable after newer evidence invalidates the old preview"
- "The same draft remains dirty and intact after another unchanged refresh and route transition, with the old token and confirmation control still absent"
- "An unchanged current-revision preview, confirmation boundary, and draft retained after refresh"
- "A regenerated preview token and displayed revision bound to N+1"
- "Exact Overview and contextual view titles, plus focused in-viewport secondary targets across direct loads and browser history"
+14 -1
View File
@@ -339,6 +339,19 @@ try {
assert.equal(await refreshedForm.locator('[name="reason"]').isDisabled(), false, 'the preserved reason remains editable');
assert.match(await refreshedForm.locator('.priority-change-status').innerText(), new RegExp(`revision ${revisionN1}`),
'the visible status identifies current task evidence');
await selectView(stalePage, 'overview');
await selectView(stalePage, 'work');
await stalePage.locator('#refresh-console').click();
await stalePage.locator('#live-refresh-status[data-generation="3"]').waitFor();
assert.equal(Number(await refreshedForm.getAttribute('data-revision')), revisionN1);
assert.equal(await refreshedTicket.locator('.priority').textContent(), 'low');
assert.equal(await refreshedForm.getAttribute('data-preview-token'), null);
assert.equal(await refreshedForm.locator('[data-priority-preview]').isVisible(), false);
assert.equal(await refreshedForm.locator('[data-priority-confirm]').count(), 0);
assert.equal(await refreshedForm.locator('[name="priority"]').inputValue(), 'urgent');
assert.equal(await refreshedForm.locator('[name="reason"]').inputValue(), 'Review this change against the current task evidence.');
assert.equal(await refreshedForm.locator('[name="priority"]').isDisabled(), false);
assert.equal(await refreshedForm.locator('[name="reason"]').isDisabled(), false);
await refreshedTicket.locator('.priority-change > summary').click();
await refreshedForm.getByRole('button', { name: 'Review change', exact: true }).click();
await refreshedForm.locator('[data-priority-confirm]').waitFor();
@@ -347,7 +360,7 @@ try {
'a current preview must be regenerated from revision N+1');
const currentToken = await refreshedForm.getAttribute('data-preview-token');
await stalePage.locator('#refresh-console').click();
await stalePage.locator('#live-refresh-status[data-generation="3"]').waitFor();
await stalePage.locator('#live-refresh-status[data-generation="4"]').waitFor();
assert.equal(await refreshedForm.getAttribute('data-preview-token'), currentToken,
'unchanged current evidence must retain its active preview');
assert.equal(await refreshedForm.locator('[data-priority-preview]').isVisible(), true);
+18 -19
View File
@@ -106,26 +106,25 @@ function invalidateStalePriorityPreviews(tasks = []) {
const ticket = form.closest('.task-ticket');
if (!ticket) continue;
const priority = form.querySelector('[name="priority"]')?.value;
const reason = form.querySelector('[name="reason"]')?.value;
const openDetails = new Set([...ticket.querySelectorAll('details[open]')]
.map((details) => details.querySelector(':scope > summary')?.textContent));
const template = document.createElement('template');
template.innerHTML = taskCard(task, currentBacklogHealth).trim();
const refreshedTicket = template.content.firstElementChild;
if (!refreshedTicket) continue;
const refreshedForm = refreshedTicket.querySelector('.priority-change-form');
if (refreshedForm) {
const priorityField = refreshedForm.querySelector('[name="priority"]');
const reasonField = refreshedForm.querySelector('[name="reason"]');
if (priorityField && priority) priorityField.value = priority;
if (reasonField) reasonField.value = reason ?? '';
priorityStatus(refreshedForm, `Task evidence advanced to revision ${currentRevision}. The older preview was cleared; review the current task before previewing again.`);
const priority = task.priority ?? 'normal';
const priorityBadge = ticket.querySelector('.ticket-topline .priority');
if (priorityBadge) {
priorityBadge.className = `priority priority-${escapeHtml(priority)}`;
priorityBadge.textContent = priority;
}
refreshedTicket.querySelectorAll('details').forEach((details) => {
if (openDetails.has(details.querySelector(':scope > summary')?.textContent)) details.open = true;
});
ticket.replaceWith(refreshedTicket);
form.dataset.revision = String(currentRevision);
delete form.dataset.previewToken;
delete form.dataset.planHash;
const priorityField = form.querySelector('[name="priority"]');
const reasonField = form.querySelector('[name="reason"]');
if (priorityField) priorityField.disabled = false;
if (reasonField) reasonField.disabled = false;
const preview = form.querySelector('[data-priority-preview]');
if (preview) {
preview.replaceChildren();
preview.hidden = true;
}
priorityStatus(form, `Task evidence advanced to revision ${currentRevision}. The older preview was cleared; review the current task before previewing again.`);
}
}
@@ -125,6 +125,20 @@ test('SCN-console-priority-preview-invalidates-on-newer-evidence: refresh preser
assert.equal(await form.locator('[name="reason"]').isDisabled(), false);
assert.match(await form.locator('.priority-change-status').innerText(), new RegExp(`revision ${revisionN1}`));
await page.locator('.console-rail a[href="#overview"]').click();
await page.locator('.console-rail a[href="#work"]').click();
await page.locator('#refresh-console').click();
await page.locator('#live-refresh-status[data-generation="3"]').waitFor();
assert.equal(Number(await form.getAttribute('data-revision')), revisionN1);
assert.equal(await ticket.locator('.priority').textContent(), 'low');
assert.equal(await form.getAttribute('data-preview-token'), null);
assert.equal(await form.locator('[data-priority-preview]').isVisible(), false);
assert.equal(await form.locator('[data-priority-confirm]').count(), 0);
assert.equal(await form.locator('[name="priority"]').inputValue(), 'urgent');
assert.equal(await form.locator('[name="reason"]').inputValue(), 'Preserve this unsent explanation across a newer task revision.');
assert.equal(await form.locator('[name="priority"]').isDisabled(), false);
assert.equal(await form.locator('[name="reason"]').isDisabled(), false);
await form.getByRole('button', { name: 'Review change', exact: true }).click();
await form.locator('[data-priority-confirm]').waitFor();
const currentToken = await form.getAttribute('data-preview-token');