Skip to content

question(papercuts): what must be true before offering this upstream or to other forks #34

Description

@nohat

Part of #22. Parked. Candidate, not verified. No work until I decide to share.

Question

What must be true before papercuts are offered to upstream, or before another fork could point its reports at its own sink? Decision 2026-10-05: build the local loop first and revisit privacy and security only when upstreaming is on the table. This issue holds the research so it is not redone.

What stays true now

The loop reads everything locally. The only boundaries are the public issue body, egress from fork servers (#23), and this question. The record's evidence and localOnly split stays in the schema as the seam; it costs nothing.

Research summary (2026-10-05)

  • Prior art for a redirectable sink. Matrix and Element's rageshake: the client uploads to a configurable URL, no URL means no upload, and the receiving server holds the GitHub token and maps app name to repo. Sentry's DSN docs recommend delivering the DSN dynamically to client-shipped apps so a store build needs no rebuild. Electron crashReporter has a configurable submitURL. OpenTelemetry's OTEL_EXPORTER_OTLP_* variables are the usual redirect convention. VS Code reads its issue-reporter target from product.json.
  • Failure modes to avoid. A fork keeping an upstream key or DSN phones home (bug(fork): fork servers send product analytics to upstream's PostHog by default #23 is the same bug for analytics). A sink that is swappable but with a payload only one server can parse (Firefox and third-party Breakpad servers).
  • Privacy patterns. Home Assistant has each producer redact its own section. Signal uploads a bundle privately and gives a public link only. Flutter and Homebrew can print what would be sent. Mozilla gates every new collection through data review.

Design sketch (if ever built)

  1. A versioned, sink-agnostic bundle with the evidence and localOnly split.
  2. Two sink kinds: local (always on) and http (POST the public evidence and a record link to a configured URL, optional bearer). A small receiver the operator runs files the issue.
  3. Resolution: user setting, then environment setting, then build default (none). Resolved on the server, so a store-built mobile app follows whichever environment it connects to and a fork needs no store rebuild.
  4. Upstream's sink is never a default. Sending needs an explicit per-report action with a preview of exactly what leaves.
  5. A pure toPublicEvidence(record) with an allowlist. Known weak points today: web route is the full pathname; provider and model are user-chosen names; sendLabel is raw DOM text; buildSha carries the app version; failed span names are not scrubbed.
  6. A capability flag so clients know whether an environment supports reports (feat(papercuts): idempotent create, retry without losing the report, and a capability flag #25 adds it).
  7. A docs/user/ section in the shipped voice.

What not to build

Background upload, anonymous ids, aggregate telemetry, a multi-sink fan-out UI, built-in Sentry, Slack, or OTLP sinks, a remote config service, a redaction DSL, or server-side issue creation inside T3 Code itself.

Alternatives and cost

Never upstream: no work, the fork keeps its loop. Upstream a minimal capture-and-local-store only: smallest PR, no sink. Full sink design above: a real feature with data governance, which is upstream's call as much as mine.

Default: stay parked. Revisit when upstream maintainers show interest or I choose to share.

Related

#22, #23, #25.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions