Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions pm-stack/aggregator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,14 +580,17 @@ tick visible on /quota.
`scripts/record-claude-launch.ts`). The aggregator merges them with
live laptop records into its durable registry.

`scripts/push-fleet-feed.sh` pushes the feed to the laptop over the
tailnet proxy route; a systemd timer on the sandbox runs it every
~5 minutes (`systemd/fleet-feed-collector.{service,timer}`). The
aggregator states the feed's age in the page provenance; a stale
feed keeps rendering. `/etc/systemd/system` does not survive
sandbox recycles, so `~/tools/init.sh` restores the units on boot
via `scripts/install-collector-units.sh` whenever the timer is not
active (#903).
The collector runs on the laptop: the `fleet-feed-collector` user
timer (declared in the pm-stack NixOS module, #3363/#3368) runs
`scripts/collect-fleet-feed.ts` every ~5 minutes and writes the feed
straight to the aggregator's state dir. The aggregator states the
feed's age in the page provenance; a stale feed keeps rendering.
The collector originally ran on the sandbox and pushed the feed
over the tailnet proxy route (`scripts/push-fleet-feed.sh`); that
sandbox timer is retired (#3362) — a stale sandbox copy kept
overwriting the laptop feed (its AA section 403'd against the
retired muse-dev project). The push script remains for manual use
only.

**Deployment (laptop):** `install.sh` copies the package to
`~/pm-stack/aggregator`, renders `.env` from
Expand Down Expand Up @@ -706,12 +709,11 @@ src/
opencode-tools/
session-identity.ts OpenCode tool: a session reports its own id (#906)
scripts/
collect-fleet-feed.ts sandbox collector: quota + sandbox attention
+ dns + registry records -> feed
push-fleet-feed.sh collect + push the feed to the laptop (~5 min timer)
collect-fleet-feed.ts collector: quota + attention + dns + registry
records -> feed (runs on the laptop, ~5 min timer)
push-fleet-feed.sh RETIRED sandbox producer: collect + push the feed
to the laptop (manual use only, #3362)
record-claude-launch.ts append a Muse launch record to the JSONL (#906)
systemd/
fleet-feed-collector.{service,timer} sandbox-side collector units
test/
render.test.ts unit derivations + render smoke
boot.test.ts boots the server, serves all views from fixtures
Expand Down
22 changes: 0 additions & 22 deletions pm-stack/aggregator/scripts/install-collector-units.sh

This file was deleted.

6 changes: 5 additions & 1 deletion pm-stack/aggregator/scripts/push-fleet-feed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
# Guard: scripts/push-fleet-feed.guard.sh fails if either pattern
# regresses.
#
# Cadence: ~5 min via fleet-feed-collector.timer (systemd, sandbox).
# RETIRED as a scheduled producer (code#3362/#3363): the collector moved
# to the laptop on 2026-10-31 and runs there as a user timer declared in
# the pm-stack NixOS module; the sandbox fleet-feed-collector timer that
# ran this script every ~5 min is deleted. Kept for manual/emergency use
# only -- running it overwrites the laptop feed with this host's collection.
set -euo pipefail

# Systemd system services get a minimal PATH (and no HOME); bun lives
Expand Down
13 changes: 8 additions & 5 deletions pm-stack/aggregator/src/feed.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// The fleet feed: a JSON file produced on the sandbox host by
// scripts/collect-fleet-feed.ts and pushed to the laptop (the sandbox
// OpenCode server binds its own loopback, and the quota sources of
// record live on the sandbox). The aggregator renders the feed as-is;
// a stale feed keeps rendering with its age stated in provenance.
// The fleet feed: a JSON file produced on the laptop by
// scripts/collect-fleet-feed.ts, run by the laptop's fleet-feed-collector
// user timer (declared in the pm-stack NixOS module, #3363/#3368) and
// written straight to the aggregator's state dir. (The collector
// originally ran on the sandbox and pushed the feed here; that sandbox
// timer is retired — a stale sandbox copy overwriting this file was
// code#3362.) The aggregator renders the feed as-is; a stale feed keeps
// rendering with its age stated in provenance.
import { readFile } from "node:fs/promises";
import type { UnmatchedCharge } from "./charges-match.ts";
import type { CheckoutDrift } from "./checkout-drift.ts";
Expand Down
4 changes: 2 additions & 2 deletions pm-stack/aggregator/src/topology.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ export function buildServices(cfg: Config): ServiceDef[] {
name: "Fleet-feed collector",
port: null,
bind: "— (no listener)",
runsAs: "sandbox systemd timer (fleet-feed-collector, ~5 min cadence)",
runsAs: "laptop systemd user timer (fleet-feed-collector, ~5 min cadence; pm-stack NixOS module)",
probe: "feed",
consumers: "the aggregator — most live facets read the feed it pushes",
consumers: "the aggregator — most live facets read the feed it writes",
breaksIfDown: "feed-backed facets go stale, then fall back to fixtures",
},
{
Expand Down
6 changes: 3 additions & 3 deletions pm-stack/aggregator/src/watchdog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export function watchdogTierItems(inputs: WatchdogInputs): TierItem[] {
"buildHealth diagnoses a feed generatedAt more than 60s in the future as a failed, never-fresh feed (#1148 watchdog); the clamped age of 0 must not silence the watchdog for the whole skew.",
now,
now,
"Check the fleet-feed collector's clock and the feed file it pushes; the card clears itself when a feed with a sane generatedAt lands.",
"Check the fleet-feed collector's clock and the feed file it writes; the card clears itself when a feed with a sane generatedAt lands.",
),
);
} else if (inputs.feedAgeMs === null) {
Expand All @@ -138,7 +138,7 @@ export function watchdogTierItems(inputs: WatchdogInputs): TierItem[] {
"The fleet-feed collector's output cannot be read, so every feed-backed facet is running on its last good data or fixtures. Diagnosed by the aggregator's health assembly (#1148 watchdog).",
now,
now,
"Check the fleet-feed collector (sandbox timer fleet-feed-collector) and the feed file it pushes; the card clears itself when a readable feed lands.",
"Check the fleet-feed collector (laptop user timer fleet-feed-collector) and the feed file it writes; the card clears itself when a readable feed lands.",
),
);
} else if (inputs.feedAgeMs > WATCHDOG_FEED_STALE_MS) {
Expand All @@ -151,7 +151,7 @@ export function watchdogTierItems(inputs: WatchdogInputs): TierItem[] {
`Feed age ${ageMsText(inputs.feedAgeMs)} is past the 15m freshness threshold (#1148 watchdog); feed-backed facets are flipping stale over the dead feed.`,
(Number.isNaN(generatedMs) ? now - inputs.feedAgeMs : generatedMs) + WATCHDOG_FEED_STALE_MS,
now,
"Check the fleet-feed collector (sandbox timer fleet-feed-collector, ~5 min cadence); the card clears itself when the feed is fresh again.",
"Check the fleet-feed collector (laptop user timer fleet-feed-collector, ~5 min cadence); the card clears itself when the feed is fresh again.",
),
);
}
Expand Down
18 changes: 0 additions & 18 deletions pm-stack/aggregator/systemd/fleet-feed-collector.service

This file was deleted.

10 changes: 0 additions & 10 deletions pm-stack/aggregator/systemd/fleet-feed-collector.timer

This file was deleted.