Repository navigation
Epic: one number on every surface — cross-surface parity (audit follow-ups) #94
Description
Part of #87.
Аудит всех 44 смердженных PR форка (2026-10-11) нашёл один повторяющийся класс ошибок: число, ход или порог, который PR объявляли «одним определением для всех», на граничных случаях расходится между поверхностями. Каждый случай воспроизводится одной командой — блок «Как проверить» в sub-issue; проверять достаточно один раз.
Поверхности, которые должны показывать одно и то же
| Поверхность | Где считается |
|---|---|
| Сайдбар (токены, ходы) | analyzeSessionFileMetadata — src/main/utils/jsonl.ts |
| Чат (чипы «Turn N») | transformChunksToConversation — src/renderer/utils/groupTransformer.ts |
| Панель Visible Context (Re-read, Loop, Wait-loop) | processSessionContextWithPhases — src/renderer/utils/contextTracker.ts |
| Колокол (бюджет хода, циклы) | TurnBudgetDetector, LoopDetector — src/main/utils/loopDetection.ts |
| Хук бюджета хода | analyzeTurn — scripts/turn-accounting.mjs |
pnpm analyze:session |
buildLedger, computeFindings — src/cli/analyzeSession.ts |
pnpm analyze:sessions |
scanSessionFile — src/cli/sessionInventory.ts |
pnpm session:sums |
buildSums — src/cli/sessionSums.ts |
Граничные случаи, на которых числа расходятся: запрос прокси без requestId (GLM), повторы одного вызова, компакт внутри хода, промпт сабагента в основном файле, релей тиммейта, сессия без user-сообщения в начале.
Sub-issues
- analyze:sessions bills proxy (GLM) requests twice: inventory dedups by requestId only #95 —
analyze:sessionsсчитает запрос прокси дважды (priority/high) - Loop thresholds differ per surface: panel flags the 2nd identical call, CLI the 3rd, bell the 4th #96 — порог Loop: панель со 2-го вызова, CLI с 3-го, колокол с 4-го
- Compaction splits a turn in the inventory and panel but not in analyze:session #97 — компакт режет ход в панели и инвентаре, но не в
analyze:session - Inline subagent prompt ends the turn for the hook and bell: budget spend under-counted #98 — промпт сабагента обнуляет ход у хука и колокола
- CLI turn numbers differ from chat chips: relays not counted, sidechain prompts counted #99 — номера ходов в CLI не совпадают с чипами чата
- Sessions that start without a user message: sidebar turn count vs chips #100 — сессии без user-сообщения в начале: счётчик ≠ чипы
- Turn-budget alert cannot be matched to its Re-read row #101 — уведомление о бюджете хода нельзя сопоставить со строкой Re-read
- session:sums checksums: rounds=turns is always true, hookParity is one-sided and off by one #102 — контрольные суммы
session:sumsне проверяют то, что обещают - Cross-surface parity test: one edge-case transcript through every consumer in CI #103 — тест паритета: один набор граничных случаев через все поверхности в CI
Связанные в других эпиках: #88 и #91 (эпик #87) — та же природа: ledger и инвентарь считают одно и то же по-разному; #90 (эпик #78) — ключ вызова, на котором стоит Loop; #74 и #79 — сверка с реальными сессиями.
Порядок
| Фаза | Ишью | Почему так |
|---|---|---|
| 0 | одна проверка каждого пункта по блоку «Как проверить» | выводы агента, автор им не доверяет |
| 1 | #103, #102 | сначала инструмент, который ловит расхождения; без него следующие PR не докажут паритет |
| 2 | #95, #96 | малые фиксы: общий ключ запроса в инвентаре, один порог Loop в @shared/constants/loopPolicy |
| 3 | решение о каноне хода в scripts/turn-accounting.mjs → #97, #98, #99, #100 |
одно решение (компакт, сабагент, релей, старт без user) для всех потребителей |
| 4 | #101 | ключ сопоставления колокола и панели зависит от решений фазы 3 |
Правила:
- одно ишью — один PR;
- в PR, меняющих числа, — «было/стало»;
- каждый фикс добавляет свою строку в тест паритета Cross-surface parity test: one edge-case transcript through every consumer in CI #103.
Activity
fix(loop): one LOOP_MIN_STREAK gate for panel, CLI and bell (#96) (#113)
test(parity): one edge-case fixture through every consumer (#103) (#132)