Skip to content

perf(monitor): make Codex transcript ingestion incremental - #92

Merged
adityathebe merged 8 commits into
mainfrom
feat/codex-ingestion-benchmarks
Aug 25, 2026
Merged

perf(monitor): make Codex transcript ingestion incremental#92
adityathebe merged 8 commits into
mainfrom
feat/codex-ingestion-benchmarks

Conversation

@adityathebe

@adityathebe adityathebe commented Aug 24, 2026

Copy link
Copy Markdown
Member

Captain reprocessed the complete Codex JSONL transcript after every append, so live-update latency and allocation grew with the full session history.

This keeps an in-memory parser and normalization checkpoint per transcript and resumes from the last complete newline. Partial records are reread on the next update, and checkpoints advance only after ingestion succeeds. Restart, parser-version changes, truncation, replacement, or source-bookkeeping drift safely fall back to a full replay.

Benchmark

benchstat compares the PR's original benchmark commit (841a46c, whole-file refresh) with the incremental implementation (829d4ca, warm nine-line append). Each side used 10 samples and 10 iterations per sample. The benchmark labels were normalized to CodexLiveUpdate because the before and after measurements intentionally exercise different production entry points.

goos: linux
goarch: amd64
pkg: github.com/flanksource/captain/pkg/monitor
cpu: Intel(R) Xeon(R) Processor @ 2.60GHz
                                            │   before.txt   │              after.txt               │
                                            │     sec/op     │    sec/op     vs base                │
CodexLiveUpdate/1000_lines_219048_bytes-8      11154.1µ ± 8%   160.8µ ± 96%  -98.56% (p=0.000 n=10)
CodexLiveUpdate/10000_lines_2198875_bytes-8   119841.1µ ± 3%   183.9µ ± 23%  -99.85% (p=0.000 n=10)
CodexLiveUpdate/25003_lines_5507854_bytes-8   286470.0µ ± 2%   192.2µ ± 12%  -99.93% (p=0.000 n=10)
geomean                                          72.62m        178.5µ        -99.75%

                                            │   before.txt    │              after.txt               │
                                            │      B/op       │     B/op      vs base                │
CodexLiveUpdate/1000_lines_219048_bytes-8      12476.6Ki ± 0%   118.3Ki ± 3%  -99.05% (p=0.000 n=10)
CodexLiveUpdate/10000_lines_2198875_bytes-8   130447.8Ki ± 0%   118.4Ki ± 1%  -99.91% (p=0.000 n=10)
CodexLiveUpdate/25003_lines_5507854_bytes-8   325956.5Ki ± 0%   118.4Ki ± 1%  -99.96% (p=0.000 n=10)
geomean                                          79.06Mi        118.3Ki       -99.85%

                                            │   before.txt   │             after.txt              │
                                            │   allocs/op    │ allocs/op   vs base                │
CodexLiveUpdate/1000_lines_219048_bytes-8       54284.0 ± 0%   578.0 ± 1%  -98.94% (p=0.000 n=10)
CodexLiveUpdate/10000_lines_2198875_bytes-8    540415.5 ± 0%   578.0 ± 1%  -99.89% (p=0.000 n=10)
CodexLiveUpdate/25003_lines_5507854_bytes-8   1350673.5 ± 0%   578.0 ± 1%  -99.96% (p=0.000 n=10)
geomean                                          340.9k        578.0       -99.83%

Warm update time and allocation are now effectively flat as the transcript grows. A cold replay remains available for restart and invalidation cases.

image

Closes #91

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 15 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ff25324-f258-40cc-a360-e7d4320b3b85

📥 Commits

Reviewing files that changed from the base of the PR and between 2de3014 and ded46b7.

📒 Files selected for processing (7)
  • pkg/ai/history/codex_events.go
  • pkg/ai/history/codex_parser.go
  • pkg/database/session_ingest_store.go
  • pkg/monitor/ingest.go
  • pkg/monitor/ingest_benchmark_test.go
  • pkg/monitor/watch.go
  • pkg/session/build_codex.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

Gavel summary

Source Pass Fail Skip Duration

Totals: 0 passed · 0 failed · 0 skipped · -

View full results

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

Gavel summary

Source Pass Fail Skip Duration
agentcreds 11 0 0 1ms
ai 87 0 0 36ms
aichat 135 0 2 15.8s
anthropicmock 1 0 0 1ms
api 223 0 0 45ms
attachments 5 0 0 3ms
bash 4 0 0 160.24µs
callertools 10 0 0 87ms
captain 17 0 0 10.6s
claude 22 0 0 36ms
claudeagent 13 0 0 248ms
cli 239 0 0 7.5s
cmux 4 0 0 290.114µs
collections 12 0 0 386.462µs
credentials 5 0 0 36ms
credsync 11 0 0 300ms
database 20 0 0 5.6s
deploy 110 0 0 175ms
genkit 25 0 0 76ms
gitagent 122 0 0 15.6s
github.com/flanksource/captain/migrations 11 0 0 4.2s
github.com/flanksource/captain/pkg/ai 250 0 0 580ms
github.com/flanksource/captain/pkg/ai/agent 26 0 0 450ms
github.com/flanksource/captain/pkg/ai/agent/commit 56 0 0 4.1s
github.com/flanksource/captain/pkg/ai/agent/setup 16 0 0 50ms
github.com/flanksource/captain/pkg/ai/agent/verify 21 0 0 390ms
github.com/flanksource/captain/pkg/ai/agent/worktree 6 0 0 -
github.com/flanksource/captain/pkg/ai/assistanttags 15 0 0 -
github.com/flanksource/captain/pkg/ai/fixture 42 0 0 140ms
github.com/flanksource/captain/pkg/ai/fixture/kubeproxy 2 0 0 30ms
github.com/flanksource/captain/pkg/ai/fixture/mcpproxy 6 0 0 -
github.com/flanksource/captain/pkg/ai/history 54 0 0 -
github.com/flanksource/captain/pkg/ai/internal/gen-model-registry 12 0 0 -
github.com/flanksource/captain/pkg/ai/middleware 25 0 0 -
github.com/flanksource/captain/pkg/ai/pricing 9 0 0 10ms
github.com/flanksource/captain/pkg/ai/prompt 16 0 0 10ms
github.com/flanksource/captain/pkg/ai/provider 169 0 1 10ms
github.com/flanksource/captain/pkg/ai/provider/claudeagent 54 0 0 1.3s
github.com/flanksource/captain/pkg/ai/provider/cmux 128 0 0 900ms
github.com/flanksource/captain/pkg/ai/provider/genkit 36 0 0 -
github.com/flanksource/captain/pkg/ai/provider/jsonrpc 6 0 0 50ms
github.com/flanksource/captain/pkg/aichat 9 0 0 100ms
github.com/flanksource/captain/pkg/aimock 50 0 7 430ms
github.com/flanksource/captain/pkg/aimock/anthropicmock 14 0 0 10ms
github.com/flanksource/captain/pkg/aimock/openaimock 18 0 0 50ms
github.com/flanksource/captain/pkg/api 143 0 0 650ms
github.com/flanksource/captain/pkg/api/registry 96 0 0 -
github.com/flanksource/captain/pkg/bash 348 0 0 60ms
github.com/flanksource/captain/pkg/captainconfig 25 0 0 -
github.com/flanksource/captain/pkg/captaintoken 23 0 0 1.8s
github.com/flanksource/captain/pkg/claude 138 0 0 -
github.com/flanksource/captain/pkg/claude/tools 18 0 0 -
github.com/flanksource/captain/pkg/cli 779 0 1 1m7s
github.com/flanksource/captain/pkg/cmux 1 0 0 -
github.com/flanksource/captain/pkg/codexconfig 10 0 0 10ms
github.com/flanksource/captain/pkg/container 72 0 1 -
github.com/flanksource/captain/pkg/database 130 0 0 18.3s
github.com/flanksource/captain/pkg/dod 11 0 0 1m0s
github.com/flanksource/captain/pkg/gitagent 31 0 0 350ms
github.com/flanksource/captain/pkg/gitagent/proxy 12 0 0 -
github.com/flanksource/captain/pkg/monitor 60 0 0 3.1s
github.com/flanksource/captain/pkg/sandbox 13 0 0 -
github.com/flanksource/captain/pkg/sandbox/adapter 39 0 0 -
github.com/flanksource/captain/pkg/sandbox/presets 13 0 0 -
github.com/flanksource/captain/pkg/session 70 0 0 10ms
history 69 0 0 15ms
migrations 12 0 0 5.0s
openaimock 2 0 0 190.368µs
provider 12 0 0 18ms
registry 38 0 0 4ms
session 28 0 0 11ms
tools 53 0 0 2ms

Totals: 4373 passed · 0 failed · 12 skipped · 3m45s

View full results

@adityathebe
adityathebe marked this pull request as ready for review August 25, 2026 06:26
Live transcript updates reparse and normalize the complete Codex rollout after every append, but the production path had no scaling baseline.

Add deterministic generated workloads for size and transcript-shape comparisons, plus phase benchmarks that isolate parsing, session construction, and final ingest mapping.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0343a-93d5-7085-bdc4-257d6f6a8e61
Whole-file Codex parsing allocated a new event receiver for every JSONL record. Decode each record into one caller-owned event, resetting it first so fields omitted by later records cannot leak across lines.

The ingestion benchmark shows about 4.8% fewer allocated bytes and one fewer allocation per transcript line while preserving parser output.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
The final chat record in a growing rollout can still receive a higher-priority twin on the next append. Treat that dedupe candidate as provisional, preserve its original source-line identity when merging, and keep synthetic EOF snapshots from closing the real record boundary.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
Retain turn, call, reasoning, and twin-dedupe state across JSONL records while releasing settled rows immediately. Whole-file extraction now wraps the same parser used by future suffix reads, and EOF snapshots do not mutate its checkpoint.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
Share Codex normalization between whole-file builds and a compact monitor checkpoint. The incremental path retains aggregate and per-turn state, emits only messages and turns touched by each append, and overlays provisional EOF rows without committing them.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
Keep one parser and compact normalizer checkpoint per rollout path, seek from the last complete JSONL record, and bound reads to a same-descriptor size snapshot. Invalidate on rewrites, replacements, identity changes, or bookkeeping drift; publish the checkpoint only after database source bookkeeping succeeds and requeue growth observed during the write.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
Keep the changed-file projection sorted as paths are first observed and order only the turns touched by the current append. Warm projections can now reuse historical aggregate slices instead of rebuilding them from every prior turn and file.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
Seed the production parser and accumulator checkpoint behind 1k, 10k, and 25k-line rollouts, then measure a fixed nine-line append without database work. Keep the existing whole-file size series as the cold replay baseline.

Amp-Thread-ID: https://ampcode.com/threads/T-01a034b2-a3f9-706d-bbb1-a2e8b6af58bb
@adityathebe
adityathebe force-pushed the feat/codex-ingestion-benchmarks branch from 829d4ca to ded46b7 Compare August 25, 2026 06:26
@adityathebe
adityathebe merged commit 2bd3a6f into main Aug 25, 2026
12 checks passed
@adityathebe
adityathebe deleted the feat/codex-ingestion-benchmarks branch August 25, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Long Codex sessions make live transcript updates increasingly expensive

1 participant