Skip to content

fix(telemetry): every send and the last-shared stamp record the origin they went to (#2571) - #2706

Merged
vybe merged 2 commits into
devfrom
feature/2571-send-log-host
Sep 11, 2026
Merged

vybe merged 2 commits into
devfrom
feature/2571-send-log-host

Conversation

@webmixgamer

Copy link
Copy Markdown
Contributor

Summary

  • The send log kept time, outcome, status and payload but not the destination, and the Usage sharing panel decided its receiver sentence by comparing the current TELEMETRY_SHARING_URL to the default at read time. That URL is a boot-time constant, so after "override → 200 → restore the default" a local sink's acknowledgement read as the hosted receiver's.
  • Every attempt now records the origin it was posted to (scheme + host + port after strip_url_credentials; never path, query or userinfo; a total reducer, stamped in the best-effort writer so no attempt is logged without one), and the 2xx stamp records the origin that acknowledged it (telemetry_sharing_last_shared_host, written before the date so a write cut in half never pairs a fresh date with a stale receiver).
  • receiver_hint is decided from the entry; the status gains receiver_host, configured_host, receiver_mismatch and last_shared_host, and share_url is scrubbed. The panel names the host that answered, says plainly when the newest send went elsewhere than the configured address and what happens next (with sharing on or off), and shows "to " per row and "Last delivered to ". Pre-existing entries and stamps read as "an unknown receiver" and never as a mismatch. No migration, no new setting.

Changes

  • src/backend/services/telemetry_sharing_service.py — _send_host / _display_url / _entry_host, the writer stamp, the entry-based hint, the status fields, the stamp origin.
  • src/frontend/src/components/onboarding/telemetryConsent.js — receiverLabel, receiverCopy over recorded/normalised origins only.
  • src/frontend/src/components/settings/TelemetrySharingPanel.vue, src/frontend/src/stores/telemetrySharing.js — render the new fields; no new palette class, no new loading gate.
  • Tests: tests/unit/test_ent437_telemetry_consent.py (six new tests, the 404 test rewritten because it pinned the read-time comparison, a router passthrough assertion), src/frontend/tests/unit/telemetryConsent.spec.js (nine new cases).
  • Docs: feature flow + index, requirements §45.2 FR-5/FR-7, docs/PRODUCT_EVENTS.md, docs/memory/architecture/backend.md, a learnings entry, the CSO diff report (no findings at the gate).

Test Plan

  • Backend: pytest tests/unit/test_ent437_telemetry_consent.py tests/unit/test_2618_heartbeat_dueness.py tests/unit/test_ent12_telemetry_sharing.py — 114 passed; test_2669_minting_accessor_callers and the settings-sink / auth-wiring / enumeration guards green.
  • Frontend: vitest run tests/unit/telemetryConsent.spec.js tests/unit/rawColorRatchet.spec.js tests/unit/loadingGateRatchet.spec.js — 48 passed; full unit suite 2702 passed.
  • Manual: on the local stack, legacy entries render "to an unknown receiver" with no mismatch; a seeded sink-200-then-default-restored state renders the mismatch sentence in light and dark; the API returns the expected verdict.

Deferred and registered in the debt inbox: a destination change starting a new delivery episode (stamp + backfill marker honoured only for the recorded origin), and the private benchmark read using the recorded origin instead of hedging.

Fixes #2571

🤖 Generated with Claude Code

…n they went to, and the receiver sentence is decided from that record (#2571)

The send log kept time, outcome, status and payload but not the destination,
and Settings → Usage sharing decided "404 at the default address" vs "your
receiver answered 404" by comparing the CURRENT TELEMETRY_SHARING_URL to the
default at read time, beside the current address. That URL is a boot-time
constant, so after "override → 200 → restore the default" a local sink's
acknowledgement read as the hosted receiver's.

Now each entry carries the origin it was posted to (scheme + host + port after
strip_url_credentials; never path, query or userinfo; total over every URL
shape, stamped in the best-effort writer so no attempt is logged without one),
the 2xx stamp records the origin that acknowledged it
(telemetry_sharing_last_shared_host, written before the date), receiver_hint
is decided from the entry, and the status carries receiver_host /
configured_host / receiver_mismatch so the panel names the host that answered,
says plainly when the newest send went elsewhere than the configured address
and what happens next, and shows "to <host>" per row and "Last delivered <date>
to <host>". Entries and stamps written before this read as "an unknown
receiver" and never as a mismatch; share_url is scrubbed. No migration, no new
setting.

Deferred (registered): a destination change starting a new delivery episode,
and the private benchmark read using the recorded origin instead of hedging.

Fixes #2571

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@webmixgamer webmixgamer added the ui PR touches the frontend UI — triggers Playwright e2e tests label Sep 11, 2026
@vybe

vybe commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

merge-train 2026-09-11: on this train. The red frontend-e2e is the #2705 pair (workspace-model-choice, agent-detail-request-dedupe) that #2714 fixes ahead of you on the same train; this PR touches nothing under src/frontend/e2e/. Every assertion executes code — the tss fixture drives the real service through share_now → _record_send → get_status, the router test asserts the four new keys ride through, 105 pytest + 2705 vitest locally.

Four mechanical nits, none blocking, yours to take or leave:

  • The panel → store → copy seam has no executing test: TelemetrySharingPanel.vue:157-163 wires store.status.{receiver_host,configured_host,receiver_mismatch,enabled} into receiverCopy, and no spec mounts the panel or calls the store; receiverCopy/receiverLabel are executed only as pure functions.
  • telemetryConsent.js:143 appends "The next scheduled send goes there." when enabled is true, but is_consent_enabled() (telemetry_sharing_service.py:294) does not fold hard_disabled — consent on + TELEMETRY_SHARING_ENABLED=false + a recorded mismatch says "nothing leaves the box" and then promises a send. enabled && !hard_disabled.
  • share_url is now a consumer-less wire field: the service scrubs it (:531), pytest asserts the scrubbed value, the panel dropped its only use (store default telemetrySharing.js:35 is dead state).
  • Body says "no new setting" — KEY_LAST_SHARED_HOST is the new system_settings key telemetry_sharing_last_shared_host (prefix-guarded; the flow doc lists it).

…host

# Conflicts:
#	docs/memory/feature-flows.md
#	docs/memory/learnings.md

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

merge-train: batch validated on train/20260911-1635 (#2729)

@vybe
vybe merged commit 00cf21c into dev Sep 11, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ui PR touches the frontend UI — triggers Playwright e2e tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants