Skip to content

Fix rpc-messages.jsonl parsing to handle real-world event/_schema format - #53256

Merged
pelikhan merged 5 commits into
mainfrom
copilot/deep-report-investigate-rpc-messages-jsonl
Aug 17, 2026
Merged

Fix rpc-messages.jsonl parsing to handle real-world event/_schema format#53256
pelikhan merged 5 commits into
mainfrom
copilot/deep-report-investigate-rpc-messages-jsonl

Conversation

Copilot AI commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Real MCP-enabled workflow runs sample rpc-messages.jsonl telemetry with 0/202 entries exposing the top-level type field the parser expected, silently zeroing out tool-call counts and durations for every run relying on this fallback (used whenever gateway.jsonl is absent — 20/20 sampled runs).

Root cause

Downloaded real rpc-messages.jsonl artifacts from recent workflow runs and confirmed: production telemetry (schema rpc-message/v2) uses a top-level event field (rpc_request / rpc_response / difc_filtered) plus a _schema marker — never the legacy top-level type field (REQUEST/RESPONSE/DIFC_FILTERED) the parser, JS summary generator, and workflow docs all assumed.

{"timestamp":"2026-08-15T23:48:42.233Z","event":"rpc_request","_schema":"rpc-message/v2","direction":"OUT","server_id":"github","payload":{...}}

Changes

  • pkg/cli/gateway_logs_types.go: RPCMessageEntry gains Event/Schema fields and an EffectiveType() method that normalizes event values to legacy type values, preferring type when both are present (no known schema populates both with conflicting values).
  • pkg/cli/gateway_logs_rpc.go / pkg/cli/gateway_logs_timeline.go: all direct entry.Type == comparisons replaced with entry.EffectiveType().
  • actions/setup/js/parse_mcp_gateway_log.cjs: matching getRpcMessageType() helper, applied in parseRpcMessagesJsonl and parseGatewayJsonlForDifcFiltered (entry.type only backfilled when absent, to avoid clobbering existing data).
  • .github/workflows/daily-observability-report.md: documented schema (Phase 3.4) updated to reflect the real event/_schema format and explicitly instructs against flagging runs unhealthy solely for missing type; lock file recompiled.
  • Regression tests (Go + JS) added covering event/_schema-only entries for REQUEST/RESPONSE/DIFC_FILTERED.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.6 AIC · ⌖ 6.8 AIC · ⊞ 6.3K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Investigate missing top-level type field in rpc-messages.jsonl Fix rpc-messages.jsonl parsing to handle real-world event/_schema format Aug 17, 2026
Copilot AI requested a review from pelikhan August 17, 2026 01:19
@pelikhan
pelikhan marked this pull request as ready for review August 17, 2026 01:26
Copilot AI balanced review requested due to automatic review settings August 17, 2026 01:26

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.

Pull request overview

Updates RPC telemetry parsing to support production rpc-message/v2 event fields while preserving legacy compatibility.

Changes:

  • Normalizes event values across Go and JavaScript parsers.
  • Updates timeline, metrics, and DIFC handling with regression tests.
  • Revises observability workflow guidance and recompiles its lock file.
Show a summary per file
File Description
pkg/cli/gateway_logs_types.go Adds v2 fields and type normalization.
pkg/cli/gateway_logs_rpc.go Uses normalized types for metrics and tool calls.
pkg/cli/gateway_logs_timeline.go Supports v2 events in timelines.
pkg/cli/gateway_logs_timeline_rpcentry_test.go Tests v2 timeline conversion.
pkg/cli/gateway_logs_test.go Tests v2 metrics and tool-call pairing.
actions/setup/js/parse_mcp_gateway_log.cjs Normalizes v2 events in summary parsing.
actions/setup/js/parse_mcp_gateway_log.test.cjs Adds JavaScript regression coverage.
.github/workflows/daily-observability-report.md Documents the production schema.
.github/workflows/daily-observability-report.lock.yml Updates compiled workflow metadata.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +42 to +45
function getRpcMessageType(entry) {
if (typeof entry?.type === "string" && entry.type) return entry.type;
if (typeof entry?.event === "string") return RPC_EVENT_TO_TYPE[entry.event] || entry.event;
return "";
Comment on lines +213 to +215
- `event` or `type`: Message kind. Real-world telemetry (schema `rpc-message/v2`) uses a
top-level `event` field with values `rpc_request` / `rpc_response` (and `difc_filtered`
for blocked events); a top-level `_schema` field (e.g. `"rpc-message/v2"`) marks this
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Reviewed PR #53256 for over-engineering per ponytail-review skill. The event/schema normalization (EffectiveType() in Go, getRpcMessageType() in JS) is a minimal, single-purpose mapping with clear precedence rules, mirrored intentionally across the two languages since Go and JS parsers don't share code. No dead code, no speculative abstractions, no unnecessary dependencies. Lean already. Ship.

Generated by Ponytail Reviewer for #53256

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-17T00:00:00Z
review_event: COMMENT
top_themes:
  - event/type normalization for rpc-message/v2 looks consistent across Go and JS paths
  - regression coverage added for request/response/difc_filtered fallback parsing
  - no actionable changed-line correctness issues found
files_reviewed:
  - .github/workflows/daily-observability-report.md
  - actions/setup/js/parse_mcp_gateway_log.cjs
  - actions/setup/js/parse_mcp_gateway_log.test.cjs
  - pkg/cli/gateway_logs_rpc.go
  - pkg/cli/gateway_logs_test.go
  - pkg/cli/gateway_logs_timeline.go
  - pkg/cli/gateway_logs_timeline_rpcentry_test.go
  - pkg/cli/gateway_logs_types.go
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 9.33 AIC · ⌖ 6.31 AIC · ⊞ 4.5K ·
Comment /review to run again

@github-actions github-actions 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.

Verdict

COMMENT — I didn't find a changed-line bug worth blocking on here.

What I checked
  • the new event → legacy type normalization is applied consistently in the Go parser, tool-call reconstruction path, and timeline conversion
  • the JS fallback summary path now accepts rpc-message/v2 entries without mutating explicit legacy type values
  • regression coverage exists for request, response, and difc_filtered cases in both languages

No actionable review comments this round.

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 9.33 AIC · ⌖ 6.31 AIC · ⊞ 4.5K
Comment /review to run again

@github-actions github-actions 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.

The fix correctly handles real-world rpc-messages.jsonl files that use the schema rpc-message/v2 format (event field instead of legacy type field).

Go: EffectiveType() method on RPCMessageEntry cleanly normalizes both formats without mutating the struct. All call sites updated to use this method.

JS: getRpcMessageType() helper with in-place normalization of entry.type for backward-compatible downstream consumers.

Tests: Solid regression coverage in both Go and JS. LGTM.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 24.9 AIC · ⌖ 7.02 AIC · ⊞ 5.6K

@github-actions github-actions Bot mentioned this pull request Aug 17, 2026

@github-actions github-actions 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.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — approving with two minor suggestions.

📋 Key Themes & Highlights

Key Themes

  • Root cause properly addressed: EffectiveType() / getRpcMessageType() centralise normalisation cleanly, rather than patching every call site.
  • Good regression test coverage: Go and JS tests both cover event-only entries for all three event types, and EffectiveType has table-driven unit tests. The issue #53254 is referenced inline.
  • Two minor observations (non-blocking): documented in inline comments above.

Positive Highlights

  • EffectiveType() gives the Go struct a clear, narrowly-scoped interface — consistent with deep-module principles.
  • legacy type takes precedence test case protects against future schema drift.
  • ✅ Documentation update in daily-observability-report.md explicitly discourages false-positive unhealthy flags — good operational hygiene.
  • ✅ Both JS and Go implementations mirror each other, reducing the cognitive distance when reading across the boundary.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 39.2 AIC · ⌖ 9.12 AIC · ⊞ 7.7K
Comment /matt to run again

// when absent so we never overwrite an entry's own explicit "type" value.
if (!entry.type) entry.type = messageType;

if (messageType === "REQUEST") {

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.

[/tdd] entry.type = messageType mutates the freshly-parsed JSON object. The comment explains why this is safe, but callers who re-serialize the result or pass it to multiple consumers may be surprised.

💡 Suggestion

The comment is helpful, but consider making the safety guarantee explicit at the call site:

// entry is a freshly-parsed object from JSON.parse(trimmed); safe to mutate.
if (!entry.type) entry.type = messageType;

Or avoid mutation entirely by normalizing before downstream consumers use the object:

const typedEntry = entry.type ? entry : { ...entry, type: messageType };

This makes the intent clearer and prevents subtle bugs if parseRpcMessagesJsonl is ever refactored to share parsed entries.

@copilot please address this.

@@ -301,10 +320,10 @@ function parseGatewayJsonlForDifcFiltered(jsonlContent) {
const lines = jsonlContent.split("\n");
for (const line of lines) {
const trimmed = line.trim();

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.

[/diagnosing-bugs] The early-exit regex /difc_filtered/i is case-insensitive but the final check via getRpcMessageType() produces "DIFC_FILTERED" (uppercase). This works today, but the case-insensitive fast-path may silently pass lines that getRpcMessageType cannot normalize (e.g. "DIFC_Filtered" in a future schema variant).

💡 Suggestion

Make the fast-path regex and the lookup consistent. Either:

  1. Use a case-sensitive regex matching both known spellings: /difc_filtered|DIFC_FILTERED/
  2. Or add a comment explaining the intentional loose match is just a perf guard and the inner getRpcMessageType check is the authoritative gate.
// Fast-path guard (loose): skip lines that obviously cannot be difc events.
// getRpcMessageType() below is the authoritative check.
if (!trimmed || !/difc_filtered|DIFC_FILTERED/i.test(trimmed)) continue;

@copilot please address this.

Documents the decision to introduce EffectiveType()/getRpcMessageType()
normalization helpers that bridge the legacy `type` field and the
production schema rpc-message/v2 `event` field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (143 new lines in pkg/ and actions/ business paths) but did not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/53256-normalize-rpc-messages-jsonl-schema-across-versions.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch at docs/adr/53256-normalize-rpc-messages-jsonl-schema-across-versions.md — it was generated from the PR diff
  2. Complete the missing sections — add any context the AI couldn't infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-53256: Normalize rpc-messages.jsonl Schema Across Versions

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 0042-use-postgresql.md for PR #42).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 · 89.3 AIC · ⌖ 15.9 AIC · ⊞ 9K ·
Comment /review to run again

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot this PR is ready for the next finishing pass.

Please address these items, newest first:

  • Unresolved review feedback:
    • Design Decision Gate: complete the drafted ADR, commit it, and link it from the PR body before merge.
  • Refresh the branch with the latest base changes.
  • Run the pr-finisher skill after the fixes and summarize the outcome.

Run: https://github.com/github/gh-aw/actions/runs/31985733953

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.6 AIC · ⌖ 6.8 AIC · ⊞ 6.3K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI requested a review from gh-aw-bot August 17, 2026 02:04
@pelikhan
pelikhan merged commit fe165f6 into main Aug 17, 2026
39 checks passed
@pelikhan
pelikhan deleted the copilot/deep-report-investigate-rpc-messages-jsonl branch August 17, 2026 02:21
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.87.1

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.

[deep-report] Investigate: rpc-messages.jsonl real telemetry may lack the top-level type field our parser expects (0/202 sampled)

4 participants