Skip to content

feat(studio): gzip run-log commits, behavior_v2 default, bridge log-level ack (PR 2 of 3) — Studio v0.72 - #186

Open
mbreiser wants to merge 1 commit into
claude/runlog-behavior-v2-bridge-d7554dfrom
claude/runlog-behavior-v2-studio
Open

feat(studio): gzip run-log commits, behavior_v2 default, bridge log-level ack (PR 2 of 3) — Studio v0.72#186
mbreiser wants to merge 1 commit into
claude/runlog-behavior-v2-bridge-d7554dfrom
claude/runlog-behavior-v2-studio

Conversation

@mbreiser

@mbreiser mbreiser commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Studio side (PR 2 of 3) of docs/development/runlog-behavior-v2-plan.md. Stacks on #183 (the bridge PR); the base is that branch and should be retargeted to main once #183 merges.

Merge order note. Once this is live, new course runs commit as .jsonl.gz, which the analysis dashboard and the replay viewer cannot open until PR 3 (readers) lands. Recommend merging PR 2 together with or after PR 3. Until then a .jsonl.gz opens with gunzip or pixi run bridge -- --convert.

What changed

arena_studio.html v0.72

  • Run logs commit gzipped. commitRunLog gzips the bridge export in the browser (GH.gzipBytes, native CompressionStream) and commits runlogs/<bench>/<name>.jsonl.gz through GH.commitFile, which uses the Contents API up to 30 MiB and the Git Database API above it (the Contents API rejects ~35 MiB+ files, which is what killed the 51 MB rig03-sr run). The log line, the upload modal and the run-summary line show raw → gzipped size and, when used, the large-file path. A browser without CompressionStream falls back to raw .jsonl.
  • File ▾ → Run logging offers behavior_v2 (compact — default), behavior_v1 (legacy) and full. Nothing stored → v2; an explicitly stored v1 is honored (one release, per the plan).
  • The bridge confirms the log level. At run start the Studio asserts the level, waits ≤ 800 ms for the bridge's log_control_ack, and names the confirmed level in the banner and the recorded transcript. When the bridge cannot write it: "⚠ bridge too old for behavior_v2 — logging behavior_v1 (restart pixi run bridge …)"; when it never answers (pre-3.0 bridge): "did not confirm … assuming behavior_v1". The Console's read-only #cFtLogLevel mirror follows the ack with a ⚠ and an explanatory tooltip on mismatch.
  • run_metadata gains log_format = the acked level, or the inferred one for a non-acking bridge (behavior_v1 when v2 was requested, else the request itself). Set from the ack, never injected by the bridge, so the v1↔v2 file round trip from feat(bridge): behavior_v2 run-log format, --convert CLI, log_control ack (PR 1 of 3) #183 stays exact.

js/fictrac-bridge-client.js

  • LOG_LEVELS = ['behavior_v2','behavior_v1','full'], default v2 (setLogLevel whitelist).
  • Handles hello_ackbridgeInfo, bridgeSupportsLevel(level) (null when unknown = old bridge) and log_control_ackackedLogLevel (cleared by every setLogging() and on close).
  • New 'loglevel' event {source, requested, level, ok, levels, enabled, file} plus an 'err' log line on mismatch; waitForLogLevelAck(ms) resolves the acked level or null.

js/studio-github.js

  • gzipBytes(input), isGzip(bytes).
  • Git Database request builders reqCreateBlob / reqGetCommit / reqCreateTree (path allowlisted) / reqCreateCommit / reqUpdateRef (fast-forward only), directCommitLarge (repo → ref → commit → blob → tree → commit → ref, per-step error reporting), commitFile (size router; LARGE_FILE_BYTES = 30 MiB; thresholdBytes test hook; result carries via + bytes).

Docs: release notes v0.72, cshl-pipeline-test-plan.md size-limits section, CLAUDE.md Studio rule (readers must inflate; log_format only from the ack), plan doc status + "PR 2 implementation notes".

Tests

  • tests/test-fictrac-bridge-client.js: 42 → 71 checks — v2 default, v1/full selectable, unknown ignored; hello_ack recorded + bridgeSupportsLevel; log_control_ack sets ackedLogLevel, resolves waiters, emits 'loglevel'; disabled ack; mismatch → ok:false + err line naming both levels; hello from a bridge lacking the level warns up front; close resets everything and resolves pending waiters null; old-bridge timeout path.
  • tests/test-studio-github.js: 118 → 160 checks — gzip round trip against zlib.gunzipSync (UTF-8 preserved), gzip magic; builders' URLs/bodies/token containment, tree refuses a non-allowlisted path; directCommitLarge exact 7-call sequence with a mocked fetch (tree on the head root tree, commit parents = head, ref moved without force), blob-failure step reporting; commitFile small → Contents path, over threshold → git-db, UTF-8 byte counting; and assertions on the Studio HTML that commitRunLog gzips, names .jsonl.gz, routes through commitFile, keeps the raw fallback, offers the v2 option and stamps log_format.
  • Full pixi run test passes; the four touched JS files are Prettier-clean; all five inline Studio script blocks parse.
  • Not tested in a browser or on a rig (no hardware for a few days). The browser-only pieces are CompressionStream (Chrome ≥ 80; same API works in Node 26, where the gzip test runs) and the Studio DOM wiring, which is asserted textually. Bench check: recorded 20 s run → .jsonl.gz committed with the size shown and the banner naming behavior_v2; then run against an old bridge checkout and confirm the "too old" warning + log_format: behavior_v1 in the file; force the Git Database path by temporarily lowering LARGE_FILE_BYTES and confirm the blob/tree/commit/ref sequence lands one file.

🤖 Generated with Claude Code

…bridge log-level ack (PR 2 of runlog-behavior-v2-plan) — Studio v0.72

Studio side of docs/development/runlog-behavior-v2-plan.md (Part 1 §5 + Part 2).
Stacks on PR #183 (bridge). Readers (dashboard / replay viewer) are PR 3 — until
it lands, .jsonl.gz files need gunzip or `bridge.py --convert`.

- js/fictrac-bridge-client.js: LOG_LEVELS [behavior_v2, behavior_v1, full]
  (v2 default); handles hello_ack (bridgeInfo, bridgeSupportsLevel) and
  log_control_ack (ackedLogLevel, cleared on every setLogging and on close);
  new 'loglevel' event + an err log line when the bridge cannot write the
  requested level; waitForLogLevelAck(ms) → acked level or null (old bridge).
- js/studio-github.js: gzipBytes (CompressionStream) + isGzip; Git Database
  builders (reqCreateBlob/reqGetCommit/reqCreateTree/reqCreateCommit/
  reqUpdateRef, allowlisted, fast-forward only); directCommitLarge (7-call
  blob→tree→commit→ref sequence, per-step errors); commitFile routes by size
  (LARGE_FILE_BYTES = 30 MiB) and reports via + bytes.
- arena_studio.html v0.72: File ▾ → Run logging offers behavior_v2 (default) /
  behavior_v1 (legacy) / full; Console mirror follows the bridge's ack (⚠ on
  mismatch); run start awaits the ack ≤ 800 ms, names the level in the banner
  + transcript and warns "bridge too old for behavior_v2 — logging behavior_v1"
  (or "did not confirm" for a pre-3.0 bridge); run_metadata gains log_format;
  commitRunLog gzips the export → runlogs/<bench>/<name>.jsonl.gz via
  GH.commitFile (raw .jsonl fallback without CompressionStream) and shows
  raw → gz size + the path used.
- Tests: test-fictrac-bridge-client.js 42 → 71 checks (levels, hello_ack,
  log_control_ack, mismatch, waiters, close reset); test-studio-github.js
  118 → 160 (gzip round trip via zlib, git-db builders + token containment,
  directCommitLarge sequence + failure step, commitFile routing, Studio wiring
  assertions on the HTML).
- Docs: release notes v0.72, cshl-pipeline-test-plan size-limits, CLAUDE.md
  Studio rule, plan doc status + PR 2 notes (merge with/after PR 3).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.

1 participant