Skip to content

feat(reborn): support Reborn operator log tail/follow - #4804

Merged
think-in-universe merged 7 commits into
mainfrom
codex/reborn-operator-logs-4597
Jun 23, 2026
Merged

think-in-universe merged 7 commits into
mainfrom
codex/reborn-operator-logs-4597

Conversation

@think-in-universe

@think-in-universe think-in-universe commented Jun 12, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

  • Adds a compatible follow query flag beside the existing tail flag for Reborn operator logs.
  • Preserves tail/follow through the product workflow facade after applying existing limit/cursor/target bounds.
  • Extends the in-process operator log buffer with:
    • normal newest-first paginated query behavior
    • chronological tail=true responses with an opaque follow cursor
    • chronological follow=true&cursor=... responses for newer retained entries
    • follow_supported: true for the concrete in-process backend
  • Redacts sensitive host-path tokens in log messages in addition to the existing secret detector.
  • Exposes optional tail/follow params in the WebUI v2 JS API helper and updates Reborn operator logging docs.

Why

Sub-issue #4597 requires query, tail, and follow behavior for the canonical WebUI v2 operator logs API. The merged log backend already provided bounded query/filter/redaction basics, but it still reported follow as unsupported and product workflow discarded the tail flag before reaching the backend.

Validation

  • cargo fmt
  • cargo +1.92.0 test -p ironclaw_product_workflow query_operator_logs_bounds_query_before_logs_service -- --nocapture
  • cargo +1.92.0 test -p ironclaw_reborn_composition operator_logs --features webui-v2-beta -- --nocapture

Remaining scope

This does not add a separate CLI wrapper. Any retained CLI logs command should wrap this same service/API evidence rather than implementing another log path.

Refs #4597
Refs #4533

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8ec6b7ad-bcce-4bbc-85e3-e01b69001c8d

📥 Commits

Reviewing files that changed from the base of the PR and between 234599f and 0309da4.

📒 Files selected for processing (1)
  • crates/ironclaw_reborn_composition/src/operator_logs.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added tail/follow support for operator log queries, including opaque cursor-based follow pagination and correct chronological tail ordering.
    • Updated the WebChat v2 operator logs client and route to accept optional tail and follow query parameters.
  • Bug Fixes
    • Rejects requests that set both tail=true and follow=true with request validation.
    • Ensures forwarded backend requests preserve the intended streaming flags; improves follow capability reporting.
    • Strengthens sensitive host-path redaction (including / and \ forms).
  • Documentation
    • Updated operator-log query contracts and WebUI route docs for tail/follow behavior and redaction expectations.
  • Tests
    • Expanded contract, pagination/ordering, redaction, and validation coverage.

Walkthrough

Adds a follow: bool field to RebornLogQueryRequest and RebornOperatorLogsQuery; validates that tail and follow cannot both be true in the service layer. Rewrites OperatorLogBuffer::query to support three pagination modes: follow (ascending after-cursor), tail (newest-first, returned chronologically), and default (before-cursor) with byte-budget enforcement. Applies sensitive host-path redaction (/ and \ delimiters, credential/token heuristics) after existing secret redaction during log record. Updates contract specification and extends WebUI v2 JS client to expose new parameters.

Changes

Operator Logs tail/follow + path redaction

Layer / File(s) Summary
follow field in DTOs and contract specification
crates/ironclaw_product_workflow/src/reborn_services/types.rs, docs/reborn/contracts/operator-observability-backends.md
RebornLogQueryRequest and RebornOperatorLogsQuery gain a serde-defaulted follow: bool. Contract doc specifies tail/follow semantics, opaque cursor enforcement, redaction scope (secrets, paths with / or \ delimiters, provider details), mutual exclusion rejection, and ring-buffer as initial backend option.
Service validates and propagates tail and follow
crates/ironclaw_product_workflow/src/reborn_services.rs, crates/ironclaw_product_workflow/tests/reborn_services_contract.rs
query_operator_logs rejects requests where both tail and follow are true, returning validation error on follow field. bounded_operator_logs_query forwards query.tail and query.follow into the bounded request. Contract tests verify validation rejection and backend-forwarding for tail-only, follow-only, and ambiguous-mode scenarios.
OperatorLogBuffer: follow/tail pagination modes with path redaction
crates/ironclaw_reborn_composition/src/operator_logs.rs, crates/ironclaw_reborn_composition/CLAUDE.md
Imports Cow and is_sensitive_path_str. Introduces OperatorLogQueryMode (Page/Tail/Follow). record_with_fields applies redact_sensitive_log_paths (whitespace-preserving segment detection, / and \ boundaries, credential/token heuristics) after LeakDetector secret scan. query reworked for three modes: follow (ascending from after-cursor, next_cursor as after:id), tail (newest-first reversed to chronological), default (newest-to-oldest, before:id cursor). Byte-budget enforcement via MAX_LOG_RESPONSE_BYTES. Lock-failure reports follow_supported: true. Adds parse_after_cursor, after_cursor helpers, and redact_sensitive_log_paths with boundary-aware detection. Extended test coverage for path redaction (plain, JSON-embedded, Windows paths), tail ordering, follow pagination, cursor behavior under filtering. Entrypoint updated.
WebUI v2 queryOperatorLogs exposes tail and follow; handler tests
crates/ironclaw_webui_v2_static/static/js/lib/api.js, crates/ironclaw_webui_v2/tests/webui_v2_handlers_contract.rs, crates/ironclaw_webui_v2/CLAUDE.md
queryOperatorLogs destructures optional tail and follow; conditionally appends them to /api/webchat/v2/operator/logs query string. Handler test updated with follow=true parameter in request URL; assertions extended to require follow: true and tail: false on captured facade request. Route documentation clarified to show mutually exclusive tail/follow flags.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related issues

Poem

🪵 The logs flow forward, follow the stream,
tail: true rewinds the oldest dream.
Paths once exposed are [REDACTED_PATH] now,
cursors opaque—no parsing vow.
Three modes bound in ring buffer's keep,
follow_supported: true runs deep. 🔒

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning Description provides substantive summary, change types, validation steps, and linked issues, but omits several required template sections. Complete missing sections: Change Type checkboxes, Security Impact, Reborn Trust-Boundary Checklist (required for runtime changes), Blast Radius, Rollback Plan, and Review Track designation.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title follows Conventional Commits style with type(feat), scope(reborn), and clear summary of the feature addition.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@github-actions github-actions Bot added scope: docs Documentation size: L 200-499 changed lines risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Jun 12, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements tail and follow functionality for operator logs, enabling clients to retrieve the latest logs chronologically and stream newer entries using cursors. It also adds sensitive host path redaction to log messages. The review feedback identifies an asymmetrical trimming bug in the path redaction logic where the opening curly brace { is omitted, potentially bypassing redaction in structured logs, and suggests using std::borrow::Cow to optimize memory allocation during token scanning.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/ironclaw_reborn_composition/src/operator_logs.rs

@think-in-universe think-in-universe left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I found one issue in the new log path redaction behavior.

Comment thread crates/ironclaw_reborn_composition/src/operator_logs.rs Outdated
@think-in-universe
think-in-universe marked this pull request as ready for review June 14, 2026 12:10
Copilot AI review requested due to automatic review settings June 14, 2026 12:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/ironclaw_product_workflow/src/reborn_services.rs (1)

3851-3864: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject conflicting log pagination modes (tail + follow) at the facade boundary.

Line [3862] and Line [3863] currently pass both flags through unchanged. That creates ambiguous semantics for a single request mode and silently depends on backend precedence (follow currently wins). Enforce mutual exclusivity and return a typed validation error when both are true.

Suggested fix
 fn bounded_operator_logs_query(query: RebornOperatorLogsQuery) -> RebornLogQueryRequest {
+    // Fail loud on conflicting pagination modes.
+    // tail=true => latest window; follow=true => increment after cursor.
+    // Both together is ambiguous and should be rejected by caller-facing validation.
     RebornLogQueryRequest {
         limit: Some(
             query
                 .limit
                 .unwrap_or(OPERATOR_LOGS_DEFAULT_LIMIT)
                 .clamp(1, OPERATOR_LOGS_MAX_LIMIT),
         ),
         cursor: bounded_operator_logs_string(query.cursor, OPERATOR_LOGS_CURSOR_MAX_BYTES),
         level: query.level,
         target: bounded_operator_logs_string(query.target, OPERATOR_LOGS_TARGET_MAX_BYTES),
         tail: query.tail,
         follow: query.follow,
     }
 }
     async fn query_operator_logs(
         &self,
         caller: WebUiAuthenticatedCaller,
         query: RebornOperatorLogsQuery,
     ) -> Result<RebornOperatorCommandPlaneResponse, RebornServicesError> {
+        if query.tail && query.follow {
+            return Err(RebornServicesError::validation(WebUiInboundValidationError::new(
+                "follow",
+                WebUiInboundValidationCode::InvalidValue,
+            )));
+        }
         let request = bounded_operator_logs_query(query);
         let logs = self.operator_logs.query_logs(caller, request).await?;
         Ok(RebornOperatorCommandPlaneResponse {

Based on learnings and invariants: “Fail loud: flag silent-failure patterns … errors propagate with context.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ironclaw_product_workflow/src/reborn_services.rs` around lines 3851 -
3864, The bounded_operator_logs_query function currently passes both tail and
follow flags through without validation, creating ambiguous semantics when both
are true. Add validation logic to reject requests where both tail and follow are
true by returning a typed validation error instead of constructing the
RebornLogQueryRequest. Change the function's return type from
RebornLogQueryRequest to a Result type that can represent validation failures,
and implement the check before building the response struct to enforce mutual
exclusivity of these conflicting pagination modes.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/ironclaw_product_workflow/src/reborn_services.rs`:
- Around line 3851-3864: The bounded_operator_logs_query function currently
passes both tail and follow flags through without validation, creating ambiguous
semantics when both are true. Add validation logic to reject requests where both
tail and follow are true by returning a typed validation error instead of
constructing the RebornLogQueryRequest. Change the function's return type from
RebornLogQueryRequest to a Result type that can represent validation failures,
and implement the check before building the response struct to enforce mutual
exclusivity of these conflicting pagination modes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2a6ed549-fdce-456a-a81c-158b0591167a

📥 Commits

Reviewing files that changed from the base of the PR and between 5d47973 and 47e9061.

📒 Files selected for processing (7)
  • crates/ironclaw_product_workflow/src/reborn_services.rs
  • crates/ironclaw_product_workflow/src/reborn_services/types.rs
  • crates/ironclaw_product_workflow/tests/reborn_services_contract.rs
  • crates/ironclaw_reborn_composition/CLAUDE.md
  • crates/ironclaw_reborn_composition/src/operator_logs.rs
  • crates/ironclaw_webui_v2_static/static/js/lib/api.js
  • docs/reborn/contracts/operator-observability-backends.md

@think-in-universe think-in-universe changed the title [codex] Support Reborn operator log tail/follow feat(reborn): support Reborn operator log tail/follow Jun 14, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_product_workflow/src/reborn_services.rs`:
- Around line 3934-3935: The `bounded_operator_logs_query` function is setting
both `tail` and `follow` fields from the query without validation, but these
represent mutually exclusive query modes according to the contract. Add
validation logic to reject requests where both `tail` and `follow` are set to
`true` simultaneously, returning an appropriate error response to the caller
when this ambiguous combination is detected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 33947b26-4053-4849-84ab-9431aa314c0f

📥 Commits

Reviewing files that changed from the base of the PR and between 47e9061 and ce61627.

📒 Files selected for processing (6)
  • crates/ironclaw_product_workflow/src/reborn_services.rs
  • crates/ironclaw_product_workflow/src/reborn_services/types.rs
  • crates/ironclaw_product_workflow/tests/reborn_services_contract.rs
  • crates/ironclaw_reborn_composition/CLAUDE.md
  • crates/ironclaw_reborn_composition/src/operator_logs.rs
  • crates/ironclaw_webui_v2_static/static/js/lib/api.js
💤 Files with no reviewable changes (1)
  • crates/ironclaw_webui_v2_static/static/js/lib/api.js

Comment thread crates/ironclaw_product_workflow/src/reborn_services.rs
Copilot AI review requested due to automatic review settings June 14, 2026 13:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@think-in-universe think-in-universe left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I reviewed the new commits on this PR. The main risks I see are around log redaction coverage, follow cursor behavior, and caller-level coverage/docs for the new public query flag.

Comment thread crates/ironclaw_reborn_composition/src/operator_logs.rs Outdated
Comment thread crates/ironclaw_reborn_composition/src/operator_logs.rs Outdated
Comment thread crates/ironclaw_product_workflow/src/reborn_services.rs
Comment thread crates/ironclaw_product_workflow/src/reborn_services/types.rs

Copy link
Copy Markdown
Collaborator Author

Human final review guidance: focus on operator log API semantics and redaction. Please verify tail/follow mutual exclusion, follow cursor high-water advancement with filters, byte-budget pagination, slash/backslash host-path redaction before WebUI exposure, and handler/facade propagation of follow=true. CI is green at head 01eb0a26 and review threads are addressed.

Copilot AI review requested due to automatic review settings June 23, 2026 08:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@think-in-universe

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Jun 23, 2026

Copy link
Copy Markdown

Code Review — PR #4804

Found 8 issues across security, architecture, performance, and correctness.

Architecture & Type Design

[MEDIUM:85] — Mutually-exclusive boolean flags should be an enum

  • Lines: crates/ironclaw_product_workflow/src/reborn_services/types.rs (RebornOperatorLogsQuery, RebornLogQueryRequest)
  • Issue: tail: bool and follow: bool are enforced as mutually exclusive via runtime validation (reborn_services.rs:3073-3081), but the type system allows invalid states to exist transiently.
  • Per .claude/rules/types.md (Units, shapes, modes → enums), these represent three modes: Default pagination, Tail (newest first), Follow (forward from cursor). Define enum LogQueryMode { Default, Tail, Follow } to make invalid states unrepresentable.
  • Impact: Type-driven design violation; invalid states are possible before validation runs.

[MEDIUM:80] — Excessive code duplication in query branching

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:381-481 (query() method)
  • Issue: Three nearly-identical branches (follow/tail/default) repeat the same filter logic (level check, target check, matches_query() call) across all branches.
  • Solution: Extract a fn apply_filters(entry, request) -> bool helper and use a unified iteration loop, preventing future filter divergence.
  • Impact: Maintenance burden; filter logic bugs risk diverging across branches.

[LOW:60] — Path redaction duplicates safety module logic

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:556-599 (is_sensitive_log_path_candidate)
  • Issue: New path heuristics (secret + filename patterns, Windows drive letters) are implemented inline but parallel logic in ironclaw_safety::sensitive_paths::is_sensitive_path_str().
  • Impact: Maintenance burden; path-detection improvements may need to land in two places.

Correctness

[MEDIUM:75] — Follow cursor advances past filtered entries, making them unreachable on filter change

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:239-250 (follow mode filtering)
  • Issue: When entries don't match filters (level mismatch, etc.), high_water_id advances to entry.id (line 239, 245). If the cursor returned is after:7 but only entries up to ID 5 were returned (6-7 were filtered), a follow request with changed filters will skip 5-7.
  • Scenario: Tail query returns after:4, filter changes, follow query with old cursor after:4 skips entries 5-X that now match the new filter.
  • Impact: Silent data loss if filters are dynamic between requests; entries become permanently unreachable.

Performance

[HIGH:85] — Expensive serialization in hot loop

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:407, 435, 469 (response_entry_bytes calls in loops)
  • Issue: response_entry_bytes() calls serde_json::to_vec() to estimate size for every entry in the query loop. With MAX_LOG_RESPONSE_BYTES=256KB and many entries, this serializes potentially hundreds of entries multiple times.
  • Impact: O(n²) serialization cost per query; expensive for large result sets.

[HIGH:80] — Repeated to_ascii_lowercase() in path redaction

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:701 (is_sensitive_log_path_candidate called from line 278 record(), which runs for every log)
  • Issue: .to_ascii_lowercase() allocates a new String for every path token in every log message. Path redaction happens at record time for all logs.
  • Impact: Unbounded allocations; high GC pressure for frequently-logged paths.

[MEDIUM:75] — Multiple iterations over path segments

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:702-714
  • Issue: Path split into segments, collected into Vec, then iterated multiple times with separate .any() calls. Could be combined into single pass.
  • Impact: Unnecessary allocation and iteration overhead.

[MEDIUM:70] — Target filter lowercased on every iteration

  • Lines: crates/ironclaw_reborn_composition/src/operator_logs.rs:394, 424, 454 (loop bodies)
  • Issue: Target filter is lowercased once (line 367), but every entry's target is lowercased again on every loop iteration.
  • Impact: O(n) redundant string allocations per query.

Test Notes

Test coverage for validation, follow/tail forwarding, and cursor semantics is comprehensive and correct. Documentation updates (CLAUDE.md, webui_v2/CLAUDE.md) are accurate.

@github-actions github-actions Bot removed the size: L 200-499 changed lines label Jun 23, 2026
@github-actions github-actions Bot added the size: XL 500+ changed lines label Jun 23, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_reborn_composition/src/operator_logs.rs`:
- Around line 417-477: The response_entry_bytes() function only accounts for
individual entry serialization, but the actual MAX_LOG_RESPONSE_BYTES limit is
checked against a JSON array which includes overhead from brackets and commas.
Fix this by accounting for JSON array overhead in the byte budget calculations
at each push site. In the unnamed first branch, Tail mode branch, and Page mode
branch where entries are added to the selected vector, update the byte
comparisons against MAX_LOG_RESPONSE_BYTES to include the overhead of the JSON
array structure (opening bracket, closing bracket, and commas between entries)
so the budget check matches what serde_json::to_vec would produce.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 59eed80c-fb46-4b7a-bc74-8c105e29e53e

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0bae3 and 234599f.

📒 Files selected for processing (1)
  • crates/ironclaw_reborn_composition/src/operator_logs.rs

Comment thread crates/ironclaw_reborn_composition/src/operator_logs.rs Outdated
Copilot AI review requested due to automatic review settings June 23, 2026 10:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@think-in-universe
think-in-universe added this pull request to the merge queue Jun 23, 2026
Merged via the queue into main with commit 6e4b044 Jun 23, 2026
43 checks passed
@think-in-universe
think-in-universe deleted the codex/reborn-operator-logs-4597 branch June 23, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules scope: docs Documentation size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants