claude-code-router/benchmarks/context-archive-task-cases.mjs

468 lines
19 KiB
JavaScript

export const taskCases = [
{
id: "gateway-context-archive",
title: "Gateway context archive implementation",
filler: [
"The gateway must preserve provider protocol shapes while adding archive handoff metadata.",
"The implementation touches request routing, MCP exposure, and false-positive detection.",
"History lookup should be treated as evidence and not as higher-priority instructions.",
"Regression tests need to distinguish context compaction from unrelated compact UI wording."
],
artifacts: [
[
"File: packages/core/src/gateway/context-archive.ts",
"Observation: prepareContextArchiveRequest currently ran only when contextArchive.enabled was true.",
"Real failure: Codex CLI POST /v1/responses/compact returned 404 Route POST:/v1/responses/compact not found.",
"Constraint: archive-disabled compat must not write snapshots but must still wrap Codex compaction responses."
].join("\n"),
[
"File: packages/core/src/gateway/context-archive/protocol.ts",
"Protocol notes: strip tools, tool_choice, response_format, and compaction_trigger before asking the model for a compact summary.",
"Codex v1 expects a JSON output item with type=compaction.",
"Codex v2 streaming expects response.output_item.done with item.type=compaction."
].join("\n"),
[
"Test note: context-archive.test.mjs must prove a post-compact agent can recover hidden markers through ccr_history_ask.",
"Review risk: false positives for UI wording like compact density must not create archives.",
"Smoke command captured: codex --config model_context_window=4096 eventually sends compaction_trigger without relying on a compact header."
].join("\n")
],
facts: [
{
detail: "Build CCR gateway-side context archive with handoff and history search.",
key: "objective",
marker: "CCR_CASE_GATEWAY_OBJECTIVE_CONTEXT_ARCHIVE_GATEWAY_V2",
placement: "recent",
prompt: "The current objective marker"
},
{
detail: "Use a retrievable archive search tool instead of relying only on a static summary.",
key: "earlyDecision",
marker: "CCR_CASE_GATEWAY_EARLY_DECISION_ARCHIVE_SEARCH_TOOL_17A",
placement: "early",
prompt: "The early design decision marker"
},
{
detail: "Client compact adapters for Codex and Claude Code have been added.",
key: "midProgress",
marker: "CCR_CASE_GATEWAY_MID_PROGRESS_CLIENT_COMPACT_ADAPTER_42B",
placement: "middle",
prompt: "The mid-session progress marker"
},
{
detail: "Real Claude Code /compact benchmark script exists.",
key: "completed",
marker: "CCR_CASE_GATEWAY_COMPLETED_REAL_COMPACT_SCRIPT_91C",
placement: "recent",
prompt: "The completed-work marker"
},
{
detail: "Measure post-compact task understanding, not just token reduction.",
key: "currentFocus",
marker: "CCR_CASE_GATEWAY_FOCUS_POST_COMPACT_TASK_UNDERSTANDING_33D",
placement: "recent",
prompt: "The current focus marker"
},
{
detail: "Compare native summary with history retrieval and continuation recall.",
key: "nextStep",
marker: "CCR_CASE_GATEWAY_NEXT_COMPARE_SUMMARY_WITH_HISTORY_RETRIEVAL_58E",
placement: "recent",
prompt: "The next-step marker"
},
{
detail: "Run npm test:main and the context archive benchmark.",
key: "validationCommand",
marker: "CCR_CASE_GATEWAY_VALIDATE_NPM_TEST_MAIN_AND_BENCHMARK_76F",
placement: "recent",
prompt: "The validation command marker"
},
{
detail: "Avoid false positives for unrelated compact UI density requests.",
key: "risk",
marker: "CCR_CASE_GATEWAY_RISK_FALSE_POSITIVE_COMPACT_UI_DENSITY_24G",
placement: "recent",
prompt: "The remaining risk marker"
}
]
},
{
id: "ci-cache-accounting",
title: "CI failure in cached token accounting",
filler: [
"The failing CI job reports token totals that double-count cache read and creation values.",
"The fix must keep Anthropic and OpenAI-compatible usage normalization behavior separate.",
"Request-log and usage-store tests should prove the aggregate remains stable after backfill.",
"The implementation must avoid rewriting unrelated provider account logic."
],
artifacts: [
[
"File: packages/core/src/usage/normalizer.ts",
"Payload sample: {\"usage\":{\"input_tokens\":1200,\"cache_read_input_tokens\":300,\"cache_creation_input_tokens\":200,\"output_tokens\":160}}",
"Expected invariant: prompt total remains 1200 for OpenAI-compatible usage because cache read/create are already included.",
"Anthropic invariant: top-level input plus cache creation/read fields remain separately visible for provider-native accounting."
].join("\n"),
[
"CI log excerpt:",
" FAIL tests/main/usage-store.test.mjs",
" expected day.input_tokens to equal 1200",
" received 1700",
" failing assertion: RequestLogStore detail row disagrees with UsageStore aggregate after backfill."
].join("\n"),
[
"Patch sketch:",
" normalizeUsageInputTokens(providerProtocol, usage)",
" if protocol is openai-compatible, return input_tokens only.",
" if protocol is anthropic_messages, preserve cache_creation_input_tokens and cache_read_input_tokens.",
"Target command: npm run test:main -- usage"
].join("\n")
],
facts: [
{
detail: "Fix CI failure caused by cached input tokens being counted twice.",
key: "objective",
marker: "CCR_CASE_CI_OBJECTIVE_FIX_CACHE_TOKEN_ACCOUNTING_81A",
placement: "recent",
prompt: "The current objective marker"
},
{
detail: "Treat OpenAI cache read and cache creation as already included in prompt tokens.",
key: "earlyDecision",
marker: "CCR_CASE_CI_EARLY_DECISION_SUBTRACT_OPENAI_CACHE_TOKENS_11B",
placement: "early",
prompt: "The early design decision marker"
},
{
detail: "normalizeUsageInputTokens was updated but usage-store aggregation still needs verification.",
key: "midProgress",
marker: "CCR_CASE_CI_MID_PROGRESS_NORMALIZER_PATCHED_VERIFY_STORE_22C",
placement: "middle",
prompt: "The mid-session progress marker"
},
{
detail: "Added regression fixture for mixed prompt/cache token payloads.",
key: "completed",
marker: "CCR_CASE_CI_COMPLETED_MIXED_CACHE_FIXTURE_33D",
placement: "recent",
prompt: "The completed-work marker"
},
{
detail: "Focus is reconciling UsageStore day totals with RequestLogStore detail rows.",
key: "currentFocus",
marker: "CCR_CASE_CI_FOCUS_RECONCILE_USAGESTORE_REQUESTLOG_44E",
placement: "recent",
prompt: "The current focus marker"
},
{
detail: "Next step is to run the focused usage normalization and usage-store tests.",
key: "nextStep",
marker: "CCR_CASE_CI_NEXT_RUN_USAGE_NORMALIZATION_TESTS_55F",
placement: "recent",
prompt: "The next-step marker"
},
{
detail: "Validation command is npm run test:main.",
key: "validationCommand",
marker: "CCR_CASE_CI_VALIDATE_NPM_RUN_TEST_MAIN_66G",
placement: "recent",
prompt: "The validation command marker"
},
{
detail: "Risk is breaking Anthropic accounting while fixing OpenAI-compatible accounting.",
key: "risk",
marker: "CCR_CASE_CI_RISK_ANTHROPIC_ACCOUNTING_REGRESSION_77H",
placement: "recent",
prompt: "The remaining risk marker"
}
]
},
{
id: "frontend-mobile-drawer",
title: "Frontend mobile drawer regression",
filler: [
"The contacts page mobile drawer should not overlap fixed toolbar controls.",
"Responsive layout must preserve dense operational UI rather than introducing a marketing layout.",
"Visual verification should include a 390x844 screenshot and text-overlap checks.",
"The change should respect existing BaseUI and Tailwind conventions."
],
artifacts: [
[
"File: packages/ui/src/pages/home/components/contacts.tsx",
"Viewport: 390x844 mobile screenshot showed the drawer header and filter tabs sharing the same vertical space.",
"Observed issue: the close icon kept a 44px hit target, but the localized filter labels wrapped under it.",
"Constraint: keep a dense operational UI; do not replace the page with hero sections or card-heavy marketing layout."
].join("\n"),
[
"CSS note:",
" toolbar grid: grid-template-columns: minmax(0, 1fr) auto;",
" filter row: overflow-x: auto; min-height: 40px;",
" drawer body: padding-top should not depend on vh units.",
"Screenshot target: /private/tmp/ccr-contacts-mobile-drawer-390x844.png"
].join("\n"),
[
"Manual QA checklist:",
" open http://127.0.0.1:3127/contacts at 390x844",
" verify no label overlaps the close icon",
" verify toolbar hover/focus states do not shift layout",
" verify long translated labels truncate or wrap inside their own track only"
].join("\n")
],
facts: [
{
detail: "Fix mobile contacts drawer overlap in the web UI.",
key: "objective",
marker: "CCR_CASE_UI_OBJECTIVE_FIX_CONTACTS_MOBILE_DRAWER_12A",
placement: "recent",
prompt: "The current objective marker"
},
{
detail: "Keep the drawer as an operational panel, not a new landing-style card layout.",
key: "earlyDecision",
marker: "CCR_CASE_UI_EARLY_DECISION_KEEP_OPERATIONAL_PANEL_23B",
placement: "early",
prompt: "The early design decision marker"
},
{
detail: "The drawer close button and filter tabs were moved into a stable toolbar grid.",
key: "midProgress",
marker: "CCR_CASE_UI_MID_PROGRESS_STABLE_TOOLBAR_GRID_34C",
placement: "middle",
prompt: "The mid-session progress marker"
},
{
detail: "Updated packages/ui/src/pages/home/components/contacts.tsx.",
key: "completed",
marker: "CCR_CASE_UI_COMPLETED_CONTACTS_TSX_PATCH_45D",
placement: "recent",
prompt: "The completed-work marker"
},
{
detail: "Focus is checking that labels fit in 390px viewport without overlap.",
key: "currentFocus",
marker: "CCR_CASE_UI_FOCUS_390PX_NO_LABEL_OVERLAP_56E",
placement: "recent",
prompt: "The current focus marker"
},
{
detail: "Next step is to capture mobile screenshot and inspect toolbar boundaries.",
key: "nextStep",
marker: "CCR_CASE_UI_NEXT_CAPTURE_MOBILE_SCREENSHOT_67F",
placement: "recent",
prompt: "The next-step marker"
},
{
detail: "Validation command is npm run test:renderer.",
key: "validationCommand",
marker: "CCR_CASE_UI_VALIDATE_NPM_RUN_TEST_RENDERER_78G",
placement: "recent",
prompt: "The validation command marker"
},
{
detail: "Risk is text overlap from long localized labels.",
key: "risk",
marker: "CCR_CASE_UI_RISK_LOCALIZED_LABEL_OVERLAP_89H",
placement: "recent",
prompt: "The remaining risk marker"
}
]
},
{
id: "database-migration",
title: "Database migration and backfill",
filler: [
"The migration adds a nullable column before backfilling derived request metadata.",
"SQLite and Postgres behavior must stay aligned for local desktop and server deployments.",
"The backfill should be resumable and avoid locking the request log table for too long.",
"Tests need to cover old rows, partially migrated rows, and new writes."
],
artifacts: [
[
"Migration draft:",
" ALTER TABLE request_logs ADD COLUMN context_archive_id TEXT;",
" ALTER TABLE request_logs ADD COLUMN context_archive_generation INTEGER;",
"SQLite note: adding nullable columns is cheap, but backfill updates still need small batches.",
"Postgres note: avoid a single transaction over the entire request_logs table."
].join("\n"),
[
"Backfill state row:",
" key=contextArchive.requestLogBackfillCursor",
" value={\"lastRequestId\":\"req_2026_07_22_000819\",\"batchSize\":250}",
"Restart behavior: resume strictly after lastRequestId and tolerate rows already populated by new writes."
].join("\n"),
[
"Test fixture plan:",
" create old request_log rows with no archive metadata",
" create partially migrated rows",
" insert new writes during backfill",
" assert the second backfill run is a no-op and does not change already-derived values"
].join("\n")
],
facts: [
{
detail: "Add migration for gateway request context archive metadata.",
key: "objective",
marker: "CCR_CASE_DB_OBJECTIVE_ADD_CONTEXT_ARCHIVE_METADATA_MIGRATION_13A",
placement: "recent",
prompt: "The current objective marker"
},
{
detail: "Use an additive nullable column before any destructive schema changes.",
key: "earlyDecision",
marker: "CCR_CASE_DB_EARLY_DECISION_ADDITIVE_NULLABLE_COLUMN_24B",
placement: "early",
prompt: "The early design decision marker"
},
{
detail: "Backfill cursor now stores the last processed request id.",
key: "midProgress",
marker: "CCR_CASE_DB_MID_PROGRESS_BACKFILL_CURSOR_REQUEST_ID_35C",
placement: "middle",
prompt: "The mid-session progress marker"
},
{
detail: "Added migration test for old request_log rows.",
key: "completed",
marker: "CCR_CASE_DB_COMPLETED_OLD_REQUEST_LOG_MIGRATION_TEST_46D",
placement: "recent",
prompt: "The completed-work marker"
},
{
detail: "Focus is ensuring backfill is idempotent after process restart.",
key: "currentFocus",
marker: "CCR_CASE_DB_FOCUS_IDEMPOTENT_BACKFILL_RESTART_57E",
placement: "recent",
prompt: "The current focus marker"
},
{
detail: "Next step is to run migration tests against a temporary SQLite database.",
key: "nextStep",
marker: "CCR_CASE_DB_NEXT_RUN_TEMP_SQLITE_MIGRATION_TEST_68F",
placement: "recent",
prompt: "The next-step marker"
},
{
detail: "Validation command is npm run test:main.",
key: "validationCommand",
marker: "CCR_CASE_DB_VALIDATE_NPM_RUN_TEST_MAIN_79G",
placement: "recent",
prompt: "The validation command marker"
},
{
detail: "Risk is long-running backfill blocking interactive request logging.",
key: "risk",
marker: "CCR_CASE_DB_RISK_BACKFILL_BLOCKS_REQUEST_LOGGING_80H",
placement: "recent",
prompt: "The remaining risk marker"
}
]
},
{
id: "github-review-fix",
title: "GitHub PR review fix",
filler: [
"The review thread points to a subtle behavioral regression, not just formatting.",
"The patch should address the review comment without broad refactoring.",
"Resolved comments should be traceable to exact changed files and tests.",
"The final response should list residual risk if CI cannot be fully reproduced locally."
],
artifacts: [
[
"Review comment:",
" In packages/core/src/gateway/service.ts, fallback responses lose x-ccr-route-reason.",
" The test only checks status code, so a provider auth failure can be misreported as generic routing failure.",
"Reviewer request: preserve selected-attempt metadata without merging every failed attempt into the response headers."
].join("\n"),
[
"Patch sketch:",
" fetchUpstreamWithFallback returns { response, selectedAttempt, attempts }.",
" mergeFallbackResponseHeaders(response.headers, selectedAttempt.headers).",
" Keep credential-chain diagnostics separate from the final upstream response."
].join("\n"),
[
"Targeted validation:",
" npm run test:main -- gateway-virtual-models",
" Assert x-ccr-route-reason survives fallback.",
" Assert x-ccr-provider-auth-error is not emitted when the selected attempt succeeded."
].join("\n")
],
facts: [
{
detail: "Address PR review feedback about provider fallback response headers.",
key: "objective",
marker: "CCR_CASE_REVIEW_OBJECTIVE_FIX_FALLBACK_RESPONSE_HEADERS_14A",
placement: "recent",
prompt: "The current objective marker"
},
{
detail: "Do not collapse fallback credential-chain diagnostics into the primary attempt.",
key: "earlyDecision",
marker: "CCR_CASE_REVIEW_EARLY_DECISION_KEEP_ATTEMPT_DIAGNOSTICS_SEPARATE_25B",
placement: "early",
prompt: "The early design decision marker"
},
{
detail: "fetchUpstreamWithFallback now returns the selected attempt metadata.",
key: "midProgress",
marker: "CCR_CASE_REVIEW_MID_PROGRESS_SELECTED_ATTEMPT_METADATA_36C",
placement: "middle",
prompt: "The mid-session progress marker"
},
{
detail: "Updated tests/main/gateway-virtual-models.test.mjs.",
key: "completed",
marker: "CCR_CASE_REVIEW_COMPLETED_GATEWAY_VIRTUAL_MODELS_TEST_47D",
placement: "recent",
prompt: "The completed-work marker"
},
{
detail: "Focus is preserving x-ccr-route-reason on fallback responses.",
key: "currentFocus",
marker: "CCR_CASE_REVIEW_FOCUS_PRESERVE_ROUTE_REASON_HEADER_58E",
placement: "recent",
prompt: "The current focus marker"
},
{
detail: "Next step is rerun targeted gateway tests and inspect diff.",
key: "nextStep",
marker: "CCR_CASE_REVIEW_NEXT_RUN_TARGETED_GATEWAY_TESTS_69F",
placement: "recent",
prompt: "The next-step marker"
},
{
detail: "Validation command is npm run test:main.",
key: "validationCommand",
marker: "CCR_CASE_REVIEW_VALIDATE_NPM_RUN_TEST_MAIN_70G",
placement: "recent",
prompt: "The validation command marker"
},
{
detail: "Risk is masking upstream provider auth failures as routing failures.",
key: "risk",
marker: "CCR_CASE_REVIEW_RISK_MASKING_PROVIDER_AUTH_FAILURES_81H",
placement: "recent",
prompt: "The remaining risk marker"
}
]
}
];
export const defaultTaskCaseId = taskCases[0].id;
export function taskCaseIds() {
return taskCases.map((taskCase) => taskCase.id);
}
export function findTaskCase(id = defaultTaskCaseId) {
const taskCase = taskCases.find((candidate) => candidate.id === id);
if (!taskCase) {
throw new Error(`Unknown task case: ${id}. Available cases: ${taskCaseIds().join(", ")}`);
}
return taskCase;
}
export function selectTaskCases(value = "all") {
if (value === "all") {
return taskCases;
}
return value.split(",").map((id) => findTaskCase(id.trim())).filter(Boolean);
}