From 8e42802fb2ae24bbf146b803981e6128facca5c9 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 10 Jul 2026 15:38:41 +0300 Subject: [PATCH 1/3] Remove app_usage telemetry entirely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What an agent calls in the app store is nobody's business. Previously a successful 'pilotctl appstore call' (CLI) and every network app invocation (daemon appstore adapter) emitted an app_usage telemetry event carrying the app ID and method name. Both emission sites are removed: - cmd/pilotctl/appstore.go: drop the post-call telemetry send. - cmd/daemon/appstore_adapter.go: remove telemetryEmitter; the appstore service now runs with a nil Telemetry emitter (documented no-op). - cmd/daemon/main.go: drop the now-unused telemetryURL/identityPath/getNodeID wiring from the adapter literal. app_usage is gone from the wire — no consent flag, no -telemetry-url can re-enable it. catalogue_viewed / appstore_view / app_installed events are unchanged and remain consent-gated. Verified with GOWORK=off (repo go.work overlays a stale app-store checkout, pre-existing breakage): go build + go vet clean, cmd/pilotctl + pkg/telemetry tests pass. Co-Authored-By: Claude Fable 5 --- cmd/daemon/appstore_adapter.go | 59 ++++++---------------------------- cmd/daemon/main.go | 3 -- cmd/pilotctl/appstore.go | 11 ------- 3 files changed, 10 insertions(+), 63 deletions(-) diff --git a/cmd/daemon/appstore_adapter.go b/cmd/daemon/appstore_adapter.go index 7c9c0507..1fff8082 100644 --- a/cmd/daemon/appstore_adapter.go +++ b/cmd/daemon/appstore_adapter.go @@ -15,67 +15,28 @@ package main import ( "context" - "encoding/json" - "time" "github.com/pilot-protocol/app-store/plugin/appstore" "github.com/pilot-protocol/common/coreapi" - "github.com/pilot-protocol/pilotprotocol/pkg/telemetry" ) type appstoreAdapter struct { - svc *appstore.Service - telemetryURL string - identityPath string - getNodeID func() int64 // called at emit time, after daemon has registered -} - -// telemetryEmitter wraps the consent-gated telemetry client to satisfy -// the appstore.TelemetryEmitter interface. Events are sent as -// "app_usage" kind with the supervisor-provided fields as payload. -// Best-effort: send errors are logged but never block the caller. -type telemetryEmitter struct { - client *telemetry.Client - getNodeID func() int64 // called lazily; valid after daemon has registered -} - -func (e *telemetryEmitter) Emit(ev appstore.TelemetryEvent) { - if e == nil || e.client == nil { - return - } - payload, err := json.Marshal(ev) - if err != nil { - return - } - var nodeID int64 - if e.getNodeID != nil { - nodeID = e.getNodeID() - } - _ = e.client.Send(telemetry.Event{ - Kind: "app_usage", - TS: time.Now().UTC().Format(time.RFC3339), - NodeID: nodeID, - Payload: payload, - }) + svc *appstore.Service } func (a *appstoreAdapter) Name() string { return a.svc.Name() } func (a *appstoreAdapter) Order() int { return a.svc.Order() } func (a *appstoreAdapter) Start(ctx context.Context, deps coreapi.Deps) error { - // Build a consent-gated telemetry client for app-usage events. - // When the URL is empty or identity is absent the client is a - // permanent no-op — the emitter never sends anything. - client := telemetry.NewClientFromIdentity(a.telemetryURL, a.identityPath, 0) - emitter := &telemetryEmitter{client: client, getNodeID: a.getNodeID} - + // No Telemetry emitter: app_usage events were removed entirely + // (2026-07-10) — what an agent calls is nobody's business. A nil + // emitter is documented no-op in the appstore module. return a.svc.Start(ctx, appstore.Deps{ - Streams: deps.Streams, - Identity: deps.Identity, - Resolver: deps.Resolver, - Events: deps.Events, - Logger: deps.Logger, - Trust: deps.Trust, - Telemetry: emitter, + Streams: deps.Streams, + Identity: deps.Identity, + Resolver: deps.Resolver, + Events: deps.Events, + Logger: deps.Logger, + Trust: deps.Trust, }) } func (a *appstoreAdapter) Stop(ctx context.Context) error { return a.svc.Stop(ctx) } diff --git a/cmd/daemon/main.go b/cmd/daemon/main.go index 5d3f2275..731f8c42 100644 --- a/cmd/daemon/main.go +++ b/cmd/daemon/main.go @@ -404,9 +404,6 @@ func main() { // against this before spawning. nil/unpinned => fail closed. CataloguePublisher: cataloguePins.Publisher, }), - telemetryURL: *telemetryURL, - identityPath: idPath, - getNodeID: func() int64 { return int64(d.NodeID()) }, }); err != nil { log.Fatalf("register appstore: %v", err) } diff --git a/cmd/pilotctl/appstore.go b/cmd/pilotctl/appstore.go index 296d4edc..d484caa9 100644 --- a/cmd/pilotctl/appstore.go +++ b/cmd/pilotctl/appstore.go @@ -2193,17 +2193,6 @@ func cmdAppStoreCall(args []string) { fatalHint("ipc_error", hint, "%v", err) } - // Emit app_usage telemetry for a successful call (consent-gated, best-effort). - if h, _ := os.UserHomeDir(); consent.GetConsent(h, "telemetry") { - turl := os.Getenv("PILOT_TELEMETRY_URL") - if turl == "" { - turl = telemetry.DefaultEndpoint - } - payload, _ := json.Marshal(map[string]string{"app_id": appID, "method": method}) - client := telemetry.NewClientFromIdentity(turl, configDir()+"/identity.json", nodeIDFromDaemon()) - _ = client.Send(telemetry.Event{Kind: "app_usage", Payload: json.RawMessage(payload)}) - } - // Maybe replace the real result with a review prompt (gated by // appstore.review_prompt feature flag + random roll). replaced, intercepted := maybeInterceptOutput(result, appID) From 06d5c4d40cd0b096678225890e0d1c6d2427e05d Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 10 Jul 2026 21:39:23 +0300 Subject: [PATCH 2/3] skills set-mode disabled: remove injected files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'disabled' should mean nothing of ours is left on disk, not merely 'stop future ticks'. set-mode disabled now runs Uninstall after persisting the mode, deleting the files the injector wrote (skills, markers, helpers) and stripping our marker block from shared files — matching what 'skills disable all' does. JSON output gains a 'removed' count. Uses the existing skillinject.Uninstall API (v0.2.3); no dependency bump. Verified with GOWORK=off (repo go.work overlays stale sibling checkouts, pre-existing breakage): go build + go vet ./cmd/pilotctl clean, cmd/pilotctl tests pass. Co-Authored-By: Claude Fable 5 --- cmd/pilotctl/skills.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cmd/pilotctl/skills.go b/cmd/pilotctl/skills.go index f63e5b4b..07ce44cd 100644 --- a/cmd/pilotctl/skills.go +++ b/cmd/pilotctl/skills.go @@ -433,8 +433,26 @@ func cmdSkillsSetMode(args []string) { if err := skillinject.SetMode(home, mode); err != nil { fatalCode("internal", "persist mode: %v", err) } + // Switching to disabled removes what we injected, so "disabled" means + // nothing of ours is left on disk — not merely "stop future ticks". + var removed int + if mode == skillinject.ModeDisabled { + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + if rep, uErr := skillinject.Uninstall(ctx, skillinject.Config{}); uErr == nil && rep != nil { + for _, r := range rep.Removals { + if r.Action == skillinject.RemovalDeleted || r.Action == skillinject.RemovalStripped { + removed++ + } + } + } + } if jsonOutput { - outputOK(map[string]interface{}{"mode": mode}) + out := map[string]interface{}{"mode": mode} + if mode == skillinject.ModeDisabled { + out["removed"] = removed + } + outputOK(out) return } modeDesc := map[string]string{ From 2ae5e76ab30dd6ca0e65fac43cc7dcba38dff9a1 Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Fri, 10 Jul 2026 21:43:02 +0300 Subject: [PATCH 3/3] go.mod: bump go directive 1.25.11 -> 1.25.12 (GO-2026-5856) govulncheck flags GO-2026-5856 (crypto/tls Encrypted Client Hello privacy leak), fixed in the standard library at go1.25.12. CI installs the toolchain via go-version-file: go.mod, so bumping the go directive pulls in the fixed stdlib and clears the vuln repo-wide. Build verified under go1.25.12. Co-Authored-By: Claude Fable 5 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 09d02b11..3e3a1bc7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/pilot-protocol/pilotprotocol -go 1.25.11 +go 1.25.12 require ( github.com/coder/websocket v1.8.15