Skip to content

feat(diagnostics): add DiagnosticsManager and the three request families - #5571

Open
aodhanroche wants to merge 1 commit into
Aodhan/260901/diagnostics-5-bundlefrom
Aodhan/260901/diagnostics-6-manager
Open

aodhanroche wants to merge 1 commit into
Aodhan/260901/diagnostics-5-bundlefrom
Aodhan/260901/diagnostics-6-manager

Conversation

@aodhanroche

@aodhanroche aodhanroche commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Stack 6/7. Based on #5570. Largest PR in the stack (~3.6k, about half of it tests) — this is the one that wires everything below into the engine.

Why

Everything under this PR is inert. DiagnosticsManager is the one place that knows how to interrogate a live engine, and it is what makes the rest reachable.

The three requests

Request Returns
GetDiagnosticsReportRequest A redacted snapshot: version, host, resolved paths, which config layer each setting came from, which secrets are set and from which file, which libraries loaded and which failed, registered projects, logging configuration.
RunHealthChecksRequest That snapshot passed through the checks, so the verdict and the facts behind it always agree.
CollectDiagnosticsRequest Report, verdict and logs assembled into a zip. Returns a download url, or a path when output_path is given.

Redaction is seeded from what the engine actually resolved

Every path builds its own Redactor from the secret values the engine resolved, not just the keys it declares. That is what catches a credential a library logged into an error message — scrubbing the settings it was declared in does nothing for the copy sitting in a log line.

Health verdicts are redacted like the bundle's copy, because a check that fails writes its own summary and that text can come straight from the network stack or the OS.

A path is refused where a file name was asked for

A requested bundle file name is joined onto the output directory, or onto the static files directory when there is no output path. ../../.ssh/config, or anything absolute, would write somewhere the caller was never told about. Refused before any of the bundle is assembled, rather than after the work is done.

Two reporting corrections worth a look

Config layers are reported as applied only when the merge actually took them, rather than whenever the file exists. A layer skipped over a parse error was otherwise presented to a support engineer as the source of the settings they were reading — pointing them at a file that had no effect.

The workspace pin is reported as the project file spells it. A resolved copy hides the mismatch that is usually the bug.

Testing

~2.1k lines across eight files, split by section of the report (config, logs, output, paths, projects, secrets) plus request-level and secrecy suites. The one that matters most is test_no_secret_value_reaches_the_report: it fills all three secret sources with different values and asserts none reaches the output.

🤖 Generated with Claude Code


The stack

PR Contents
1 #5566 Session log buffer + rotating log files, and the settings for them
2 #5567 Share the .env merge order (pure refactor)
3 #5568 Report data model + the redactor
4 #5569 The six health checks
5 #5570 The bundle writer
6 #5571 DiagnosticsManager + the three request families
7 #5461 The CLI commands (gtn self info, gtn doctor, gtn diagnostics collect) and the docs

Review bottom-up. Each was verified independently with make check and the full unit suite.

Wires the pieces below this into the engine. `DiagnosticsManager` is the one
place that knows how to interrogate a live engine, and it answers three
requests:

- `GetDiagnosticsReportRequest` -- a redacted snapshot: version, host, resolved
  paths, which config layer each setting came from, which secrets are set and
  from which file, which libraries loaded and which failed, registered projects,
  logging configuration.
- `RunHealthChecksRequest` -- that snapshot passed through the checks, so the
  verdict and the facts behind it always agree.
- `CollectDiagnosticsRequest` -- report, verdict and logs assembled into a zip.

Every path builds its own `Redactor` seeded from the secret values the engine
actually resolved, so a credential a library logged into an error message is
scrubbed from log text and not merely from the settings it was declared in.
Health verdicts are redacted like the bundle's copy, because a check that fails
writes its own summary and that text can be an exception straight from the
network stack or the OS.

A requested bundle file name is refused if it is a path rather than a name. The
name is joined onto the output directory, or onto the static files directory
when there is no output path, so `../../.ssh/config` would otherwise write
somewhere the caller was never told about. Checked before any of the bundle is
assembled.

Config layers are reported as applied only when the merge actually took them,
rather than whenever the file exists, so a layer skipped over a parse error is
not presented to a support engineer as the source of the settings they are
reading. The workspace pin is reported as the project file spells it, since a
resolved copy hides the mismatch that is usually the bug.

Co-Authored-By: Claude Opus 5 <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