feat: compaction indicator in token bar#428
Conversation
Telos items from the Python script were never ingested into workloadStore, so the promote endpoint always returned 404. The frontend now sends item data (title, contextHints, sources) as fallback fields in the promote request body, and the endpoint uses them when workloadStore.get() misses. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove misleading `as string` cast on taskHint, use nullish coalescing - Make sources author/snippet optional in schema for real-world data - Omit `item` from response when not in workloadStore (cleaner contract) - Remove comment coupling schema to specific caller - Add tests for fallback promote path and no-broadcast behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detect SDK compaction content blocks and emit compaction_status events so the frontend can show a pulsing amber COMPACTING label instead of appearing to hang. Includes safety reset on query end and crash-safe handling of compaction_delta events. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TokensState now has a compacting boolean — update all test fixtures that construct the type directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 4 issue(s) (1 warning).
server/__tests__/workload-routes.test.ts
Well-structured feature with good test coverage for the happy path. The main concern is the broadcast-interception test for the promote fallback path, which passes vacuously due to monkey-patching a non-existent property; the compaction safety-reset path also lacks test coverage.
- 🟡 missing_tests (L548): This test is ineffective — it monkey-patches
(app as any)._workloadBroadcast, but that property does not exist on the app object. The actual broadcast callback is the module-level closureonWorkloadBroadcast(set viasetWorkloadBroadcast()in index.ts, never called in the test harness). SinceonWorkloadBroadcastis alwaysnullin tests, the assertionexpect(workloadBroadcasts).toHaveLength(0)passes vacuously for every promote call, not just the fallback path. The test doesn't verify what it claims.[fixable]
server/__tests__/token-update.test.ts
Well-structured feature with good test coverage for the happy path. The main concern is the broadcast-interception test for the promote fallback path, which passes vacuously due to monkey-patching a non-existent property; the compaction safety-reset path also lacks test coverage.
- 🔵 missing_tests (L449): The safety reset at query-loop.ts:573-581 (compaction flag reset on result when the SDK crashes/aborts before sending the system status success signal) has no test coverage. Only the happy path (content_block_start → system status success) is tested. A test with compaction started but result arriving without a preceding system status success would exercise the warn+reset path.
[fixable]
server/query-loop.ts
Well-structured feature with good test coverage for the happy path. The main concern is the broadcast-interception test for the promote fallback path, which passes vacuously due to monkey-patching a non-existent property; the compaction safety-reset path also lacks test coverage.
- 🔵 style (L970): Compaction content_block_start still runs the generic registration at lines 900-902 (blockIdByIndex.set + openBlockCount++) before reaching the compaction branch. The blockId and index mapping are unused — at content_block_stop, the code finds the blockId but then no snapshot block exists, so block_end is silently skipped. The openBlockCount stays balanced (incremented then decremented), so this is harmless, but a brief comment noting this intentional fall-through would prevent future confusion.
[fixable]
packages/client/src/protocol-parser.ts
Well-structured feature with good test coverage for the happy path. The main concern is the broadcast-interception test for the promote fallback path, which passes vacuously due to monkey-patching a non-existent property; the compaction safety-reset path also lacks test coverage.
- 🔵 style (L525):
msg.active as booleanis a bare type assertion on an untyped message field. Other cases in this switch use similar casts (e.g.,msg.agentContext as number), so this is consistent with the codebase, but aBoolean(msg.active)coercion would be more defensive against unexpected payloads.[fixable]
| expect(res.body.item).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('POST /api/workload/items/:id/promote — fallback does not broadcast workload update', async () => { |
There was a problem hiding this comment.
🟡 missing_tests: This test is ineffective — it monkey-patches (app as any)._workloadBroadcast, but that property does not exist on the app object. The actual broadcast callback is the module-level closure onWorkloadBroadcast (set via setWorkloadBroadcast() in index.ts, never called in the test harness). Since onWorkloadBroadcast is always null in tests, the assertion expect(workloadBroadcasts).toHaveLength(0) passes vacuously for every promote call, not just the fallback path. The test doesn't verify what it claims. [fixable]
| @@ -429,6 +447,12 @@ describe('token_update emission', () => { | |||
| // The final token_update should include numCompactions: 1 | |||
| const last = tokenUpdates[tokenUpdates.length - 1]; | |||
| expect(last).toMatchObject({ numCompactions: 1 }); | |||
There was a problem hiding this comment.
🔵 missing_tests: The safety reset at query-loop.ts:573-581 (compaction flag reset on result when the SDK crashes/aborts before sending the system status success signal) has no test coverage. Only the happy path (content_block_start → system status success) is tested. A test with compaction started but result arriving without a preceding system status success would exercise the warn+reset path. [fixable]
| blockType: 'text', | ||
| }), | ||
| ); | ||
| } else if (blockType === 'compaction') { |
There was a problem hiding this comment.
🔵 style: Compaction content_block_start still runs the generic registration at lines 900-902 (blockIdByIndex.set + openBlockCount++) before reaching the compaction branch. The blockId and index mapping are unused — at content_block_stop, the code finds the blockId but then no snapshot block exists, so block_end is silently skipped. The openBlockCount stays balanced (incremented then decremented), so this is harmless, but a brief comment noting this intentional fall-through would prevent future confusion. [fixable]
| break; | ||
| } | ||
|
|
||
| case 'compaction_status': |
There was a problem hiding this comment.
🔵 style: msg.active as boolean is a bare type assertion on an untyped message field. Other cases in this switch use similar casts (e.g., msg.agentContext as number), so this is consistent with the codebase, but a Boolean(msg.active) coercion would be more defensive against unexpected payloads. [fixable]
- Add comment documenting intentional blockId fall-through for compaction blocks - Use Boolean() coercion instead of bare type assertion in parser - Add test for safety reset path (compaction started, success signal missing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 4 issue(s) (1 warning).
server/__tests__/workload-routes.test.ts
Clean two-feature PR (compaction indicator + promote fallback). The compaction lifecycle is well-structured with proper safety nets. One test (fallback does not broadcast) has a broken interception mechanism that makes it pass vacuously rather than verifying the guard logic.
- 🟡 missing_tests (L548): The 'fallback does not broadcast workload update' test intercepts
(app as any)._workloadBroadcast, but that property doesn't exist on the Express app. The actual broadcast function is the module-levelonWorkloadBroadcastclosure, set viasetWorkloadBroadcast(). SinceonWorkloadBroadcastis never set in this test suite, it's alwaysnull, so the test passes vacuously — it would pass even if theif (updatedItem)guard were removed. The assertion verifies the correct outcome but doesn't actually test the code path.[fixable] - 🔵 style (L512): The renamed test description
'returns 404 for missing item with no body title'is slightly awkward — it reads as though the body has 'no body title' rather than 'no title in body'. Consider'returns 404 when item not found and body has no title'.[fixable]
server/app.ts
Clean two-feature PR (compaction indicator + promote fallback). The compaction lifecycle is well-structured with proper safety nets. One test (fallback does not broadcast) has a broken interception mechanism that makes it pass vacuously rather than verifying the guard logic.
- 🔵 style (L1929): When the item isn't found AND no title is provided, a 404 is returned with
'Item not found and no title provided'. A 404 is semantically correct for a missing resource, but when the item is intentionally absent (Telos fallback path) and the real issue is the missingtitlefield, a 400 would more accurately convey that the request body is incomplete. Minor — current behavior is workable since the only caller always provides a title.[fixable]
server/__tests__/token-update.test.ts
Clean two-feature PR (compaction indicator + promote fallback). The compaction lifecycle is well-structured with proper safety nets. One test (fallback does not broadcast) has a broken interception mechanism that makes it pass vacuously rather than verifying the guard logic.
- 🔵 missing_tests (L447): No test covers the safety-net path where the
resultevent arrives whilecompactingis still true (i.e., SDK crashed or skipped thecompact_result: 'success'system message). This would verify the warn log and the fallbackcompaction_status: active: falseemission. The logic is straightforward but it's a defensive branch worth covering.[fixable]
| expect(res.body.item).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('POST /api/workload/items/:id/promote — fallback does not broadcast workload update', async () => { |
There was a problem hiding this comment.
🟡 missing_tests: The 'fallback does not broadcast workload update' test intercepts (app as any)._workloadBroadcast, but that property doesn't exist on the Express app. The actual broadcast function is the module-level onWorkloadBroadcast closure, set via setWorkloadBroadcast(). Since onWorkloadBroadcast is never set in this test suite, it's always null, so the test passes vacuously — it would pass even if the if (updatedItem) guard were removed. The assertion verifies the correct outcome but doesn't actually test the code path. [fixable]
| }); | ||
|
|
||
| it('POST /api/workload/items/:id/promote — returns 404 for missing item', async () => { | ||
| it('POST /api/workload/items/:id/promote — returns 404 for missing item with no body title', async () => { |
There was a problem hiding this comment.
🔵 style: The renamed test description 'returns 404 for missing item with no body title' is slightly awkward — it reads as though the body has 'no body title' rather than 'no title in body'. Consider 'returns 404 when item not found and body has no title'. [fixable]
|
|
||
| const hints = item?.contextHints ?? body.data.contextHints; | ||
| const taskHint = hints?.taskHint ?? undefined; | ||
|
|
There was a problem hiding this comment.
🔵 style: When the item isn't found AND no title is provided, a 404 is returned with 'Item not found and no title provided'. A 404 is semantically correct for a missing resource, but when the item is intentionally absent (Telos fallback path) and the real issue is the missing title field, a 400 would more accurately convey that the request body is incomplete. Minor — current behavior is workable since the only caller always provides a title. [fixable]
| @@ -429,6 +447,12 @@ describe('token_update emission', () => { | |||
| // The final token_update should include numCompactions: 1 | |||
There was a problem hiding this comment.
🔵 missing_tests: No test covers the safety-net path where the result event arrives while compacting is still true (i.e., SDK crashed or skipped the compact_result: 'success' system message). This would verify the warn log and the fallback compaction_status: active: false emission. The logic is straightforward but it's a defensive branch worth covering. [fixable]
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 3 issue(s) (1 warning).
server/__tests__/workload-routes.test.ts
Compaction indicator is well-implemented with proper state lifecycle (including defensive reset on SDK crash). Promote fallback logic is sound, but the 'no broadcast' test is broken — it monkey-patches a non-existent app property instead of the module-scoped callback, passing vacuously.
- 🟡 bugs (L550): Test 'fallback does not broadcast workload update' monkey-patches
(app as any)._workloadBroadcast, but the actual broadcast callback is a module-scoped closure variableonWorkloadBroadcastset viasetWorkloadBroadcast(). The test creates a property on theappobject that nothing reads, so the assertion passes vacuously — the broadcast is never intercepted. Furthermore,setWorkloadBroadcastis never called in the test setup, soonWorkloadBroadcastisnulland no broadcast fires at all. This test proves nothing about the fallback path's broadcast behavior.[fixable] - 🔵 style (L512): The test description was renamed to 'returns 404 for missing item with no body title' but the test body only sends
{ description: '' }— consider also adding a test that sends neithertitlenordescription(empty body) to cover the pure 404 case.[fixable]
server/app.ts
Compaction indicator is well-implemented with proper state lifecycle (including defensive reset on SDK crash). Promote fallback logic is sound, but the 'no broadcast' test is broken — it monkey-patches a non-existent app property instead of the module-scoped callback, passing vacuously.
- 🔵 style (L1922): When the item doesn't exist and no
body.data.titleis provided, the error response is404with'Item not found and no title provided'. A404is debatable when the real issue is a missing required field —400would be more accurate for the 'no title provided' case. Consider splitting:404when!item && !body.data.title, vs keeping404for a true 'not found'. Minor since the frontend always sends a title for Telos items.[fixable]
|
|
||
| it('POST /api/workload/items/:id/promote — fallback does not broadcast workload update', async () => { | ||
| const broadcasts: unknown[] = []; | ||
| const origBroadcast = (app as any)._workloadBroadcast; |
There was a problem hiding this comment.
🟡 bugs: Test 'fallback does not broadcast workload update' monkey-patches (app as any)._workloadBroadcast, but the actual broadcast callback is a module-scoped closure variable onWorkloadBroadcast set via setWorkloadBroadcast(). The test creates a property on the app object that nothing reads, so the assertion passes vacuously — the broadcast is never intercepted. Furthermore, setWorkloadBroadcast is never called in the test setup, so onWorkloadBroadcast is null and no broadcast fires at all. This test proves nothing about the fallback path's broadcast behavior. [fixable]
| }); | ||
|
|
||
| it('POST /api/workload/items/:id/promote — returns 404 for missing item', async () => { | ||
| it('POST /api/workload/items/:id/promote — returns 404 for missing item with no body title', async () => { |
There was a problem hiding this comment.
🔵 style: The test description was renamed to 'returns 404 for missing item with no body title' but the test body only sends { description: '' } — consider also adding a test that sends neither title nor description (empty body) to cover the pure 404 case. [fixable]
|
|
||
| // Resolve title and context from workloadStore item or fallback body data (Telos items) | ||
| const title = item?.title ?? body.data.title; | ||
| if (!title) { |
There was a problem hiding this comment.
🔵 style: When the item doesn't exist and no body.data.title is provided, the error response is 404 with 'Item not found and no title provided'. A 404 is debatable when the real issue is a missing required field — 400 would be more accurate for the 'no title provided' case. Consider splitting: 404 when !item && !body.data.title, vs keeping 404 for a true 'not found'. Minor since the frontend always sends a title for Telos items. [fixable]
Summary
type: 'compaction') and emitcompaction_statusevents to the frontendcompaction_deltaevents are explicitly skipped, compaction blocks don't create phantom snapshot stateFiles changed
server/query-loop.ts— detect compaction blocks, emit status events, safety resetfrontend/src/components/TokenBar.tsx— compacting state renders amber indicatorfrontend/src/styles/global.css— pulsing amber animationfrontend/src/types/ws-messages.ts—CompactionStatusMsgtypepackages/client/src/slices/tokens.ts—compacting: booleaninTokensStatepackages/client/src/protocol-parser.ts— parsecompaction_statusserver/__tests__/token-update.test.ts— full compaction block lifecycle coveragepackages/client/__tests__/protocol-parser.test.ts— compaction_status parsingTest plan
🤖 Generated with Claude Code