diff --git a/packages/core/src/task-store/audit-ops.ts b/packages/core/src/task-store/audit-ops.ts index 8db6e14467..32f9d50a16 100644 --- a/packages/core/src/task-store/audit-ops.ts +++ b/packages/core/src/task-store/audit-ops.ts @@ -249,6 +249,7 @@ export async function logEntryImpl(store: TaskStore, id: string, action: string, const archivedLanes = await resolveArchivedLanes(store); const rowIsArchivedLane = archivedLanes ? archivedLanes.has(String(pgRow.column ?? "")) + /* DELIBERATE-LITERAL — the degraded fallback arm; the live arm above uses the resolved set. */ : pgRow.column === "archived"; if (rowIsArchivedLane || pgRow.deletedAt != null) { throw new Error(`Task ${id} is archived — logging is read-only`); diff --git a/packages/core/src/task-store/lifecycle-ops.ts b/packages/core/src/task-store/lifecycle-ops.ts index 4a626ca667..755bd4a9d9 100644 --- a/packages/core/src/task-store/lifecycle-ops.ts +++ b/packages/core/src/task-store/lifecycle-ops.ts @@ -660,7 +660,7 @@ export async function checkForChangesImpl(store: TaskStore): Promise { which throw in PostgreSQL backend mode, so this whole polling replica path is legacy SQLite only. - Recorded rather than converted, for the same reason as `mission-store.ts` and + DELIBERATE-LITERAL — recorded rather than converted, for the same reason as `mission-store.ts` and `project-store-ops.ts`: an unconverted literal in dead code is not debt a fleet pass should spend a signature change on, but it must not read as missed either. */ diff --git a/packages/core/src/task-store/moves.ts b/packages/core/src/task-store/moves.ts index 892020623f..422a16bb84 100644 --- a/packages/core/src/task-store/moves.ts +++ b/packages/core/src/task-store/moves.ts @@ -343,6 +343,7 @@ export async function handoffToReviewImpl(store: TaskStore, taskId: string, opts */ const taskIsArchived = handoffArchivedLanes && handoffArchivedLanes.size > 0 ? handoffArchivedLanes.has(task.column) + /* DELIBERATE-LITERAL — the degraded fallback arm; the live arm above uses the resolved set. */ : task.column === "archived"; if (taskIsArchived || task.deletedAt != null) { throw new HandoffInvariantViolationError( diff --git a/packages/core/src/task-store/task-id-integrity.ts b/packages/core/src/task-store/task-id-integrity.ts index c771958085..fef3d40269 100644 --- a/packages/core/src/task-store/task-id-integrity.ts +++ b/packages/core/src/task-store/task-id-integrity.ts @@ -437,11 +437,13 @@ export function isTaskArchivedImpl(store: TaskStore, id: string): boolean { correct without touching it. Left counted so the census keeps pointing here, and deliberately NOT converted in isolation: a - sync function with no store-scoped workflow read cannot resolve a lane, and converting this one + A sync function with no store-scoped workflow read cannot resolve a lane, and converting this one while `getLiveTaskColumn` still keys on the literal would leave the two disagreeing about what archived means. */ const cached = store.taskCache.get(id); + /* DELIBERATE-LITERAL — see the note above: sync, no store-scoped workflow read, and converting + this alone would disagree with `getLiveTaskColumn`, which still keys on the literal. */ return cached?.column === "archived"; } diff --git a/packages/engine/src/notification/notification-service.ts b/packages/engine/src/notification/notification-service.ts index 99d1887b42..5435de38b7 100644 --- a/packages/engine/src/notification/notification-service.ts +++ b/packages/engine/src/notification/notification-service.ts @@ -1239,9 +1239,18 @@ export class NotificationService { happen in `handleTaskUpdated`, which would then pay it on every task update, so it wants the same gate-placement judgement applied to the sites above rather than a mechanical pass. - Left counted, with no exemption marker, so the census keeps pointing here. + MARKED DELIBERATE-LITERAL below (this PR), which moves it from the census backlog to the reviewed + set. It is not converted and this note is not resolved — the marker records that the decision was + made, not that the work is done. Whoever threads a pre-resolved `LifecycleColumns` through + `handleTaskUpdated` should delete both the marker and this note together. */ private isManualMergeHold(task: Task): boolean { + /* DELIBERATE-LITERAL — see the note above: this method and its only caller + (`classifyWorkflowTransitionNotification`) are SYNC, reached from the `handleTaskUpdated` + listener the store invokes as `(task: Task): void`. Resolving a lane here makes that whole + chain async, turning a synchronous listener body into fire-and-forget and reordering + notification classification against every other `task:updated` handler — a behaviour change to + notification ordering rather than a column conversion. */ if (task.column !== "in-review") { return false; } diff --git a/packages/engine/src/scheduler.ts b/packages/engine/src/scheduler.ts index cb2859dc27..f0a108f528 100644 --- a/packages/engine/src/scheduler.ts +++ b/packages/engine/src/scheduler.ts @@ -1270,7 +1270,9 @@ export class Scheduler { */ // Track mission failure signals before moveTask clears failure metadata. if (task.sliceId && task.status === "failed") { - if (task.column === "in-progress") this.failedTaskIds.add(task.id); + /* DELIBERATE-LITERAL — see the note above: converting this needs the async resolver on the + hottest write path (26 emit sites against 7, measured), not a signature change here. */ + if (task.column === "in-progress") this.failedTaskIds.add(task.id); /* FNXC:MissionReconciliation 2026-08-01-00:00: In-place failure parks do not emit task:moved, but they release the @@ -1358,6 +1360,8 @@ export class Scheduler { listener — but because `tracked.has(task.id)` below is a re-entrance guard, and moving this answer behind an await lets two updates for the same task both pass it and double-start a monitor. LEFT COUNTED. See the fuller note on the mission-failure guard above. */ + /* DELIBERATE-LITERAL — see the note directly above: an await here lets two updates for the + same task both pass the `tracked.has` re-entrance guard and double-start a monitor. */ if (task.column !== "in-review") return; if (!task.prInfo) return; diff --git a/packages/engine/src/triage.ts b/packages/engine/src/triage.ts index eb44920117..487bca3bad 100644 --- a/packages/engine/src/triage.ts +++ b/packages/engine/src/triage.ts @@ -805,7 +805,7 @@ export class TriageProcessor { layer up." So the arm goes back to the literal, which is honest about being one and keeps this file's census entry pointing at work that is still outstanding. - THE SPECIFICATION IS ABOVE. Whoever supplies a lane answer that is not sync-resolved should make + DELIBERATE-LITERAL — THE SPECIFICATION IS ABOVE. Whoever supplies a lane answer that is not sync-resolved should make this line read `disposeLanes.wip` and delete this note. LEFT COUNTED until then. */ if (task.column === disposeLanes.hold || task.column === disposeLanes.intake || task.column === "in-progress") return; diff --git a/scripts/lib/lifecycle-column-census-baseline.json b/scripts/lib/lifecycle-column-census-baseline.json index e3f2fa25ac..5dd2b794a8 100644 --- a/scripts/lib/lifecycle-column-census-baseline.json +++ b/scripts/lib/lifecycle-column-census-baseline.json @@ -1,19 +1,14 @@ { "generatedFrom": "node scripts/lifecycle-column-census.mjs --strict --update-baseline", "byFile": { - "packages/engine/src/scheduler.ts": 2, - "packages/core/src/task-store/audit-ops.ts": 1, - "packages/core/src/task-store/lifecycle-ops.ts": 1, - "packages/core/src/task-store/moves.ts": 1, - "packages/core/src/task-store/task-id-integrity.ts": 1, "packages/dashboard/app/components/ResearchTaskActionModal.tsx": 1, - "packages/engine/src/notification/notification-service.ts": 1, - "packages/engine/src/self-healing.ts": 1, - "packages/engine/src/triage.ts": 1 + "packages/engine/src/self-healing.ts": 1 }, "deliberateByFile": { "packages/core/src/task-store/async-comments-attachments.ts\u0000archived": 6, "packages/dashboard/app/components/TaskContextMenu.tsx\u0000in-review": 3, + "packages/engine/src/scheduler.ts\u0000in-progress": 3, + "packages/engine/src/scheduler.ts\u0000in-review": 3, "packages/engine/src/self-healing.ts\u0000in-review": 3, "packages/core/src/live-agent-count.ts\u0000in-progress": 2, "packages/core/src/live-agent-count.ts\u0000in-review": 2, @@ -21,8 +16,10 @@ "packages/core/src/task-merge.ts\u0000archived": 2, "packages/core/src/task-merge.ts\u0000done": 2, "packages/core/src/task-merge.ts\u0000in-review": 2, + "packages/core/src/task-store/audit-ops.ts\u0000archived": 2, "packages/core/src/task-store/project-store-ops.ts\u0000in-review": 2, "packages/core/src/task-store/task-artifacts-ops.ts\u0000archived": 2, + "packages/core/src/task-store/task-id-integrity.ts\u0000archived": 2, "packages/dashboard/app/components/TaskCard.tsx\u0000todo": 2, "packages/dashboard/app/components/TaskCard.tsx\u0000triage": 2, "packages/dashboard/app/components/TaskContextMenu.tsx\u0000archived": 2, @@ -34,8 +31,6 @@ "packages/engine/src/cli-agent/state-machine.ts\u0000done": 2, "packages/engine/src/scheduler.ts\u0000archived": 2, "packages/engine/src/scheduler.ts\u0000done": 2, - "packages/engine/src/scheduler.ts\u0000in-progress": 2, - "packages/engine/src/scheduler.ts\u0000in-review": 2, "packages/engine/src/self-healing.ts\u0000done": 2, "packages/engine/src/triage.ts\u0000triage": 2, "packages/engine/src/usage-limit-detector.ts\u0000archived": 2, @@ -61,10 +56,10 @@ "packages/core/src/task-move-disposer.ts\u0000in-progress": 1, "packages/core/src/task-move-disposer.ts\u0000todo": 1, "packages/core/src/task-store/archive-lifecycle-2.ts\u0000archived": 1, - "packages/core/src/task-store/audit-ops.ts\u0000archived": 1, "packages/core/src/task-store/branch-and-pr-entities.ts\u0000archived": 1, "packages/core/src/task-store/comments-ops.ts\u0000archived": 1, - "packages/core/src/task-store/task-id-integrity.ts\u0000archived": 1, + "packages/core/src/task-store/lifecycle-ops.ts\u0000archived": 1, + "packages/core/src/task-store/moves.ts\u0000archived": 1, "packages/core/src/task-store/task-store-helpers.ts\u0000in-progress": 1, "packages/core/src/task-store/task-store-helpers.ts\u0000todo": 1, "packages/core/src/task-store/task-update.ts\u0000in-progress": 1, @@ -112,9 +107,11 @@ "packages/engine/src/hold-release.ts\u0000archived": 1, "packages/engine/src/hold-release.ts\u0000done": 1, "packages/engine/src/hold-release.ts\u0000in-review": 1, + "packages/engine/src/notification/notification-service.ts\u0000in-review": 1, "packages/engine/src/project-engine.ts\u0000in-review": 1, "packages/engine/src/scheduler.ts\u0000todo": 1, "packages/engine/src/self-healing.ts\u0000archived": 1, + "packages/engine/src/triage.ts\u0000in-progress": 1, "plugins/fusion-plugin-even-realities-glasses/src/notifications/diff.ts\u0000done": 1, "plugins/fusion-plugin-reports/src/store/report-types.ts\u0000archived": 1 },