Skip to content

feat(core,storage): add TraceQuery filtering, TraceView DTO, and store query/clear#9

Merged
epli2 merged 5 commits into
mainfrom
claude/ai-agent-ux-plan-rex4nj
Jul 12, 2026
Merged

feat(core,storage): add TraceQuery filtering, TraceView DTO, and store query/clear#9
epli2 merged 5 commits into
mainfrom
claude/ai-agent-ux-plan-rex4nj

Conversation

@epli2

@epli2 epli2 commented Jul 12, 2026

Copy link
Copy Markdown
Owner
  • phantom-core: TraceQuery (method/status/url/time-range/trace_id filters)
    with a pure matches() predicate; StatusRange parses "404", "4xx",
    "400-499"; TraceView + RenderOptions as the shared agent-facing JSON
    shape (max_body truncation, headers_only, header redaction, body size
    reporting); HttpMethod FromStr; SpanId/TraceId from_hex.
  • phantom-storage: TraceStore::query via bounded by_time range scan
    (by_trace_id prefix scan when trace_id is set) with offset applied
    after filtering; TraceStore::clear via batch removes.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky

claude added 5 commits July 12, 2026 02:35
…e query/clear

- phantom-core: TraceQuery (method/status/url/time-range/trace_id filters)
  with a pure matches() predicate; StatusRange parses "404", "4xx",
  "400-499"; TraceView + RenderOptions as the shared agent-facing JSON
  shape (max_body truncation, headers_only, header redaction, body size
  reporting); HttpMethod FromStr; SpanId/TraceId from_hex.
- phantom-storage: TraceStore::query via bounded by_time range scan
  (by_trace_id prefix scan when trace_id is set) with offset applied
  after filtering; TraceStore::clear via batch removes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky
…code propagation

Breaking: the flat CLI is replaced by subcommands.
  phantom run    -- capture (old default behavior; same flags)
  phantom list   -- filtered listing (--method/--status 4xx/--url/--since 10m/
                    --until/--trace-id/--limit/--offset, --format jsonl|json|table,
                    --max-body/--headers-only/--redact-header)
  phantom get    -- single trace by span ID (exit 1 when not found)
  phantom search -- positional URL-substring shorthand for list
  phantom stats  -- store statistics as JSON
  phantom clear  -- delete all traces (requires --yes)
  phantom mcp    -- reserved (stub, implemented next)

Agent/scripting fixes:
- Propagate the traced child's exit status (was discarded — phantom always
  exited 0); Unix signal deaths map to 128+signal.
- tracing output now goes to stderr (was stdout, could corrupt JSONL).
- Machine-readable end-of-run summary on stderr in jsonl mode:
  {"event":"exit","child_exit_code":N,"traces_captured":N}
- Global --quiet suppresses status lines; global --data-dir.
- run --max-body / --headers-only control JSONL body size.

phantom-storage: FjallTraceStore::open now takes an advisory flock on
phantom.lock — fjall itself does not lock across processes, so two phantom
instances (e.g. a query during a capture) could previously open the same
keyspace concurrently and risk corruption. Query commands surface a
lock hint pointing at the running process.

main.rs split into cli.rs, runner.rs, commands/{run,query}.rs.
Existing integration tests updated to the run subcommand; new
tests/cli_query_integration.rs covers exit codes, JSONL purity,
query filters, truncation, and the lock UX.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky
Serves the Model Context Protocol over stdio using the official rmcp SDK
(v2.2). One process hosts both capture control and trace queries, so the
store's single-process lock is never contended.

Tools (7):
- start_capture: spawn a command through the MITM proxy (Node/PHP/Java
  transparent HTTPS injection reused from the CLI runner), or a
  proxy-only session; auto-assigns a free port when none given
- capture_status / stop_capture: session lifecycle, child exit codes,
  live trace counts
- list_traces: filtered listing (method, status class/range, URL
  substring, time range, trace_id, pagination); bodies default to
  256 bytes to protect agent context
- get_trace: full detail by span ID (4 KiB default body cap, 0 = off)
- get_stats / clear_traces (confirm-guarded)

Sensitive headers (authorization, cookie, set-cookie,
proxy-authorization) are redacted by default in tool output.
Store calls run on spawn_blocking; sessions are torn down (children
killed, proxies stopped) when the client disconnects.

Register with: claude mcp add phantom -- phantom mcp

tests/mcp_stdio_integration.rs drives the server with raw JSON-RPC over
stdio: handshake, tools/list, a traced curl capture round-trip, filter
and truncation checks, and clean shutdown on stdin EOF.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky
…nd MCP server

AGENTS.md (= CLAUDE.md): new project layout (cli/runner/commands/mcp
modules), run-subcommand build examples, CLI structure tables (global
flags, run flags, query flags), exit-code and store-lock behavior,
extended JSONL schema (*_body_bytes / *_body_truncated), new MCP Server
section with tool table and Claude Code registration, test index and
data-flow updates. GEMINI.md and crate AGENTS.md files aligned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky
… MCP

phantom-core (view.rs):
- no truncation flag when the body fits max_body exactly
- max_body 0 at the core layer empties the body and flags it
- lossy UTF-8 decoding keeps the original byte size
- redaction matches header names case-insensitively
- sensitive_headers() covers all credential-carrying headers

phantom-storage:
- open-ended since-only / until-only time-range scans
- limit 0 falls back to the default page size of 100

binary unit tests (commands/query.rs):
- parse_time: RFC3339, relative durations (30s/10m/2h/1d = that long
  ago), garbage rejection
- build_query rejects malformed --trace-id
- render_options: 0 = unlimited, redact list lower-casing

tests/cli_query_integration.rs:
- SIGKILLed child maps to exit 137 (unix)
- --quiet suppresses status lines and the exit summary while still
  propagating the exit code
- run --max-body truncates the live JSONL stream and the stderr summary
  counts captured traces; run --headers-only reduces only the stream,
  the store keeps full bodies
- list --method/--since/--until/--trace-id/--format json/--redact-header
- invalid arguments fail fast: bad --status exits 2 via clap, bad
  span/trace IDs and bad --since exit 1 with clear messages

tests/mcp_stdio_integration.rs:
- tool error paths: unknown/malformed span_id, unknown session, bad
  method/status/trace_id filters, clear_traces without confirm
- proxy-only session: no child, external curl through the returned
  proxy_url is captured, stop reports the final count
- sensitive-header redaction on by default in list_traces/get_trace,
  raw value only with redact_sensitive_headers: false

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjmmAVFHuaU4Fb46QEd6ky
@epli2
epli2 merged commit 04a80eb into main Jul 12, 2026
3 checks passed
@epli2
epli2 deleted the claude/ai-agent-ux-plan-rex4nj branch July 12, 2026 09:54
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.

2 participants