Skip to content

Make ToC channel lazy to avoid file creation at log_level 0 - #105

Merged
lukstafi merged 2 commits into
mainfrom
ludics/gh-ppx-minidebug-60-s6/root
Apr 5, 2026
Merged

Make ToC channel lazy to avoid file creation at log_level 0#105
lukstafi merged 2 commits into
mainfrom
ludics/gh-ppx-minidebug-60-s6/root

Conversation

@lukstafi

@lukstafi lukstafi commented Apr 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Gate ToC file creation on log_level > 0 in shared_config (covers Flushing backend)
  • Add lazy get_toc_ch() in PrintBox functor that creates the ToC file on first access using config.with_toc_listing/toc_flame_graph and debug_ch_name(), supporting runtime log_level changes
  • Add for_append field to printbox_config so the lazy path respects the caller's open mode
  • Add test verifying no files created at log_level 0 with with_toc_listing=true
  • Shared_config public API unchanged (table_of_contents_ch : out_channel option)

Fixes #60

Test plan

🤖 Generated with Claude Code

When with_table_of_contents=true and log_level=0, the ToC file was
created eagerly even though no entries would be written. Fix by:

- Gate ToC creation on log_level > 0 in shared_config (covers Flushing)
- Add lazy get_toc_ch() in PrintBox functor that creates the ToC file
  on first access using config.with_toc_listing/toc_flame_graph and
  debug_ch_name(), supporting runtime log_level changes
- Add for_append field to printbox_config so the lazy path respects
  the caller's open mode (truncate vs append)
- Add test verifying no files created at log_level 0

Fixes #60

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lukstafi
lukstafi force-pushed the ludics/gh-ppx-minidebug-60-s6/root branch from 064e202 to 81682f2 Compare April 5, 2026 13:38
@lukstafi

lukstafi commented Apr 5, 2026

Copy link
Copy Markdown
Owner Author

@codex review Focus on bugs, correctness issues, and edge cases. Do not check adherence to a spec or plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81682f2f19

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread minidebug_runtime.ml

let table_of_contents_ch =
if with_table_of_contents then (
if with_table_of_contents && log_level > 0 then (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep ToC available after log level starts at 0

The new && log_level > 0 guard makes shared_config.table_of_contents_ch permanently None for file-backed debug_flushing runtimes created with ~log_level:0 ~with_table_of_contents:true. That runtime still allows logging later via Debug_runtime.log_level := ... (and can log level-0 entries immediately), but Flushing.close_log only emits ToC rows when table_of_contents_ch is Some, so ToC output is silently lost for the whole run in these cases.

Useful? React with 👍 / 👎.

Comment thread minidebug_runtime.ml
Comment on lines +1665 to 1666
(match get_toc_ch () with
| None -> ()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rewind lazy ToC channel during snapshots

Switching ToC writes to get_toc_ch () means snapshot code can now write to a lazily-created ToC file, but snapshot rewind still operates on Log_to.table_of_contents_ch from shared_config. When that field is None (e.g. runtime initialized with log_level=0), snapshot_ch/reset_to_snapshot never track the new channel, so periodic snapshots (snapshot_every_sec) can leave duplicate/stale ToC entries instead of rolling them back.

Useful? React with 👍 / 👎.

Shadow snapshot_ch/reset_to_snapshot in PrintBox functor to track
the lazily-created ToC channel. When table_of_contents_ch is None
(lazy case), the wrapper flushes/rewinds the lazy channel directly.
When table_of_contents_ch is already Some, defers to Log_to's
implementations which already handle it.

Fixes Codex review: snapshot_every_sec could leave stale ToC
entries when the ToC channel was created lazily.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lukstafi
lukstafi merged commit 91d4db1 into main Apr 5, 2026
0 of 6 checks passed
@lukstafi

lukstafi commented Apr 5, 2026

Copy link
Copy Markdown
Owner Author

Retrospective: What I'd do differently

1. Clarify API-stability constraints upfront

This PR took 5 review rounds largely because I didn't ask early whether changing Shared_config was acceptable. Round 1 changed the type; round 2 reverted it; round 3 re-introduced it; round 4 finally found an approach that kept the API stable. Next time: before touching a public module type, check whether breaking changes are permitted and, if not, design the solution around that constraint from the start.

2. Consider the functor-internal lazy pattern first

The final approach — keeping Shared_config unchanged and adding lazy creation inside the PrintBox functor using its mutable config record — was available from round 1. The mutable config fields (with_toc_listing, toc_flame_graph) are set after functor creation but before any logging, making them ideal for deferred decisions inside a lazy block. This pattern (functor-internal lazy gated on mutable config) is reusable for similar problems in this codebase.

3. Don't forget snapshot interactions

The Codex review caught that snapshot_ch/reset_to_snapshot in shared_config didn't know about the lazily-created ToC channel. When adding a new channel-creation path, always audit all functions that flush/seek/rewind channels. A grep for the channel name across all backends would have caught this earlier.

4. Squash iterative commits before review

The 5-commit chain of back-and-forth changes made rebasing painful and the review history hard to follow. Next time: squash into a clean commit before requesting review, or at least before rebasing onto upstream.

5. Potential future cleanup

  • The for_append field on printbox_config is only used by the lazy ToC path. If Shared_config is ever updated in a breaking release, for_append could move there instead, and the lazy ToC logic could move back to shared_config for both backends.
  • The Flushing backend still uses the init-time log_level > 0 gate. If Flushing is kept beyond 3.0, it would need the same lazy treatment (likely via a similar functor-internal approach, though Flushing lacks a mutable config record today).

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.

When with_table_of_contents=true, the ToC file is created even when the log level starts and stays at 0

1 participant