Repository navigation
Outbound Fleet reporting: report token scope, metrics --push, push after each Command (#2069) - #2086
Merged
Merged
Conversation
This was referenced Nov 12, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A machine the watching Console cannot reach inbound, such as a sleeping or NATted laptop VM, now pushes its own Run metrics summary outward. It uses a holder-bound
reporttoken, both by hand and after each Command. The Console shows that machine read-only in Fleet Metrics.sequenceDiagram participant Worker as lima-thirdshift (worker) participant Hub as always-on Console Note over Hub: console token create lima-thirdshift --scopes report Worker->>Hub: console report add hub <address> (token on stdin): GET /api/v1/whoami Hub-->>Worker: holder lima-thirdshift, scopes [report] Note over Worker: metrics --push, or Command finished (5 s, warn-only) Worker->>Hub: POST /api/v1/metrics/report {machine, view, summary} Hub->>Hub: machine == holder? not this Console's own name? save the holder's reported slot (locked, renamed in place) Hub-->>Worker: 200 {machine, pushed_at}Worker side:
console report add|list|remove, CLI-only, stored inconsole.reportin User config and[report]in Credentials.metrics --push [<destination>], which takes the window and filter flags.Started::finishpushes after a top-level Command. A skipped Pass and a child Run don't push.ADR 0026 and the parity inventory list
metrics --pushandconsole report add|list|removeas CLI-only. The report endpoint's CLI pair ismetrics --push.Docs:
docs/guide.mdgains "Reporting outward" and thereportrow in the scope table.site/docs/index.htmlis regenerated.site/index.html,site/how-it-works/andsite/architecture/are updated.Evidence
Execution evidence
issue-2036, 3722e41):cargo test --test console metrics_report, 4 passed.a_report_token_writes_only_its_holders_snapshot_and_reaches_nothing_else: uploads its holder's report; 403 for another machine; 403 on every OpenAPI operation needingread,security,act,runoradmin(more than 40 checked).metrics_push_shows_the_worker_read_only_on_the_receiving_fleet: pushes to a loopback Console;/metricsand?machine=<holder>show reported, read-only,(just now), failures without links; a revoked token gives a 401 push failure.a_finished_command_reports_its_metrics_and_an_offline_console_only_warns: a scripted Run pushes. With the Console stopped, the next Run exits 0 and logswarning: metrics not reported to hub: ….a_report_from_this_hosts_own_name_is_refused_or_shown: the Spec reviewer's test. At 1eadbce it failed withreport accepted with 200 but never shown; it now passes (422).cargo test --bin thirdshift console::passes, includingevery_cli_command_has_an_api_twin_or_reasoned_exclusion,adr_lists_every_cli_only_reasonandevery_console_route_has_a_cli_equivalent.npm run docs:check --prefix sitepasses.npm test --prefix sitepasses 68 of 68.npm test --prefix consolepasses.scripts/affected-tests refs/remotes/origin/issue-2036selected the full Rust suite. It ran withcargo test --no-fail-fastand every test passed except two pre-existing flakes:processfindings::merged_fix_is_rechecked_after_a_later_fix_failsfails 4 of 6 runs on the unmodified baseissue-2036too.triage_passrecommendation_only_pass_reserves_without_claiming_or_publishing_and_notifieshit its "agent never started" deadline under full-suite load and passes alone.Visual evidence
Publishing captures to a secret Gist was refused by this session's permission check, so no images are embedded. The captures were taken with Playwright Chromium at
1440×900and390×844. Each build served one hub home holding the same pushedlaptop-vmsnapshot (two failed and two succeededSpec runs,/metrics?window=7d):/tmp/before-desktop.NQJG88.pngand/tmp/before-mobile.Vq8Dzv.png: the base reads the pushed file as its owner's own snapshot. It showslaptop-vm: cached, offline · last seen … · no longer in this Console's Fleet, and Where runs failed promises that "each name opens its details"./tmp/after-desktop.yHmp5b.pngand/tmp/after-mobile.fTFa4m.png:laptop-vm: reported, read-only · pushed 2026-11-12 07:26 UTC (just now), in the same muted colour as cached. Where runs failed listswidgets#72 (reported) on laptop-vm, widgets#73 (reported) on laptop-vmwith no links, and says a cached or reported machine's details cannot be opened from here. The phone layout is unchanged apart from the longer intro text.Unaddressed findings
Standards
MetricsArgs.pushandpush_toas a data clump. Partly addressed:push_tois now documented (src/args.rs,MetricsArgs). The fields stay separate because the parity identity keys on the action alone (src/console/parity.rs:Command::Metrics(asked) => if asked.push { "push" } …), andpush_tois an optional target of that action.MetricsReport::localleavesmachineblank. Partly addressed: its doc now says the sender names each destination's holder. The summary is computed once and named per destination (src/console/report.rs,push), because each destination may have issued its token to a different holder; rebuilding it per destination would recompute trends from the logs for each one.FleetPage::ageduplicatesstatus::age. Declined. The Metrics page writes "N minutes ago" as page copy beside a "pushed " stamp, whilesrc/logs/status.rsageproduces the Inbox's compact "N min". Sharing one would change one page's wording.Spec
src/logs/metrics/outcomes.rs:60-64,idle_or_pass_through("a skipped Pass: neither did work of its own, so no trend counts it"), anddocs/guide.md:342. A push after it would resend an unchanged summary. The guide states the rule.Security review outcome
No unaddressed introduced findings.
Review coverage
refs/remotes/origin/issue-2036, reviewed at 1eadbce.site/docs/index.html, generated fromdocs/guide.md. Both reviewers accepted the exclusion:npm run docs:check --prefix siteis clean, andnpm test --prefix sitepasses.tests/console/api.rs(reportadded to the allowedx-scopevalues), plus the review fixes in 6f037bd and e66994a.Merge Danger
Door: two-way
Data written by this change:
console.reportUser config key;[report]Credentials section;pushed_atfield, beside the existing files underlogs/fleet-metrics/.A build without this change reads a reported snapshot as a cached, retired machine, as the Before captures show. It rejects a User config that contains
console.report.Blast Radius: Fleet
What it touches:
fleet::whoamiprobe.identityis optional, so older Consoles still pair.Scope::ALLis renamedScope::PERSON.Closes #2069
Built with claude 2.1.314 · opus · default effort