Public: anyone can read this; the crew can change it.

A gate whose install downloads from the npm registry says so in its log with the bytes, and /capacity names the repository that fetched most in the last hour #8394

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

When a check, gate or preview runs its install inside a cell and that install receives more than 1 MiB from `registry.npmjs.org`, its log now ends with `install fetched N MiB from the npm registry; the shared cache missed`. `/capacity` and MCP `capacity` also name the repository the registry sent the most to in the last hour.

shipped production is serving it deploy eb43263

opened this

When a check, gate or preview runs its install inside a cell and that install receives more than 1 MiB from registry.npmjs.org, its log now ends with install fetched N MiB from the npm registry; the shared cache missed. /capacity and MCP capacity also name the repository the registry sent the most to in the last hour.

Where the repository comes from. meterEgress(label, repoId?) in src/apps/egress.ts now takes the repository id from the code that opened the cell (repo.id for checks and gates, record.repoId for apps), never from anything the install printed. While a meter is running, recordEgress counts that label's registry bytes per repository, minute by minute over the last hour, with the same 60-minute ring the per-destination counts use. At most 256 repositories are kept; past that, the one that fetched least this hour is dropped. Each meter also has npm(), which counts registry bytes only, so a large download from GitHub does not set off the line. Registry traffic with no meter, or with a meter that has no repository, goes into the hourly total but is attributed to no repository.

The log line. npmMissLine in src/checks/install.ts decides when to write it (strictly more than 1 MiB). It is written in two places:

  • Checks and gates (src/checks/service.ts): straight after the existing install fetched … from the registry line.
  • Previews and production (src/apps/process.ts install): contained installs are now metered under the cell's label, and the line goes to the deploy log. Installs outside a cell are not metered here either.

What capacity shows. egressHour(db) in src/actions/capacity.ts turns the top repository's id into owner/name, giving egress.npmTopRepoLastHour: { repo, bytes } | null. It is null when no metered install fetched anything, or when that repository has been deleted. The egress-npm line on /settings/capacity adds "…, most to owner/name (N MiB)". The capacity tool gained a field rather than a new tool, and its doc string grew by a few words. docs/MCP.md and docs/METRICS.md describe both additions.

Tests. bun test passed on all 8 files run, with the mcp-size limits unchanged. bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts were also clean. scripts/fast.ts selected 1470 files, so I picked the 8 that cover the change.

  • test/egress-npm-repo.test.ts (new):

- 3 MiB writes the line; 512 KiB and exactly 1 MiB do not. - Bytes from other hosts don't count, and bytes after stop() aren't the install's. - Two repositories' installs are each attributed to their own repository, and the hour ages out. - Registry traffic with no meter or no repository is attributed to nobody.

  • test/capacity.test.ts: MCP and the page name alice/npm-heavy with 5.0 MiB, and give null once the tally is reset.

Not done: no test runs a full contained install from start to finish. Cells cannot run in this sandbox, so the tests drive the meter and npmMissLine directly, and the two places that write the line are not tested. I also didn't add the top repository to the terminal's Egress screen or /metrics.

To try it: as a site admin, open /settings/capacity on the preview after a check has installed with a cold cache, or call MCP capacity and read egress.npmTopRepoLastHour.

🤖 Generated with Claude Code

Closes #8382

commented

When a check, gate or preview runs its install inside a cell and that install receives more than 1 MiB from registry.npmjs.org, its log now ends with install fetched N MiB from the npm registry; the shared cache missed. /capacity and MCP capacity also name the repository the registry sent the most to in the last hour.

Where the repository comes from. meterEgress(label, repoId?) in src/apps/egress.ts now takes the repository id from the code that opened the cell (repo.id for checks and gates, record.repoId for apps), never from anything the install printed. While a meter is running, recordEgress counts that label's registry bytes per repository, minute by minute over the last hour, with the same 60-minute ring the per-destination counts use. At most 256 repositories are kept; past that, the one that fetched least this hour is dropped. Each meter also has npm(), which counts registry bytes only, so a large download from GitHub does not set off the line. Registry traffic with no meter, or with a meter that has no repository, goes into the hourly total but is attributed to no repository.

The log line. npmMissLine in src/checks/install.ts decides when to write it (strictly more than 1 MiB). It is written in two places:

  • Checks and gates (src/checks/service.ts): straight after the existing install fetched … from the registry line.
  • Previews and production (src/apps/process.ts install): contained installs are now metered under the cell's label, and the line goes to the deploy log. Installs outside a cell are not metered here either.

What capacity shows. egressHour(db) in src/actions/capacity.ts turns the top repository's id into owner/name, giving egress.npmTopRepoLastHour: { repo, bytes } | null. It is null when no metered install fetched anything, or when that repository has been deleted. The egress-npm line on /settings/capacity adds "…, most to owner/name (N MiB)". The capacity tool gained a field rather than a new tool, and its doc string grew by a few words. docs/MCP.md and docs/METRICS.md describe both additions.

Tests. bun test passed on all 8 files run, with the mcp-size limits unchanged. bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts were also clean. scripts/fast.ts selected 1470 files, so I picked the 8 that cover the change.

  • test/egress-npm-repo.test.ts (new):

- 3 MiB writes the line; 512 KiB and exactly 1 MiB do not. - Bytes from other hosts don't count, and bytes after stop() aren't the install's. - Two repositories' installs are each attributed to their own repository, and the hour ages out. - Registry traffic with no meter or no repository is attributed to nobody.

  • test/capacity.test.ts: MCP and the page name alice/npm-heavy with 5.0 MiB, and give null once the tally is reset.

Not done: no test runs a full contained install from start to finish. Cells cannot run in this sandbox, so the tests drive the meter and npmMissLine directly, and the two places that write the line are not tested. I also didn't add the top repository to the terminal's Egress screen or /metrics.

To try it: as a site admin, open /settings/capacity on the preview after a check has installed with a cold cache, or call MCP capacity and read egress.npmTopRepoLastHour.

🤖 Generated with Claude Code

Changes requested — before the latest push

No high security finding: the repository id comes from the code that opened the cell, the map is capped at 256, the page output is escaped, and the capacity read is admin-only. Three things block it.

  1. The terminal does not get the new figure (both doors). /settings/capacity and MCP now name the top repository, but the terminal's Egress connections screen (src/tui/) does not. docs/METRICS.md still says that screen "prints the same line", which is now false. Print npmTopRepoLastHour there from the same egressHour(db), with a TUI test. Fix this first.
  1. Neither of the two places that write the new log line is tested. The check/gate site in src/checks/service.ts and the app/preview site in src/apps/process.ts install() are the user-visible behaviour of this pull. Delete either and every test stays green. Inject a metered install, or extract the "meter, step, log the miss" step into a function that can be driven without a cell. Then assert that the log ends with install fetched N MiB from the npm registry; the shared cache missed.
  1. The repository can be lost. meterEgress keeps the repoId of the first holder of a label. If an earlier holder opened the label without one, a later holder's repoId is silently ignored. Set it when it is undefined, and add a test.

Smaller: the miss-line check in process.ts runs in a finally, so a failed or aborted install also logs it. That is fine, but say so in the doc comment.

commented

When a contained check, gate or app/preview install gets more than 1 MiB from registry.npmjs.org, its log now ends with install fetched N MiB from the npm registry; the shared cache missed. The forge also counts registry bytes for each repository over the last hour. The one with the most shows up in three places, all read from the same egressHour(db):

  • the Egress connections card on /settings/capacity;
  • MCP capacity, as egress.npmTopRepoLastHour;
  • the terminal's Egress connections screen.

The repository comes from the code that opened the cell, never from anything the install printed (#8382).

Changes since review:

  • Terminal: src/tui/screens/egress.ts now prints The npm registry sent X over the last hour, most to owner/name (Y).. test/egress-admin.test.ts asserts that line. docs/METRICS.md names egressHour as the source for all three places.
  • Both log sites tested: the meter / install / log steps are now one function, meteredInstall in src/checks/install.ts. Both src/checks/service.ts and install() in src/apps/process.ts call it. test/egress-npm-repo.test.ts covers:

- the check case: the 7546 fetched line, then the miss line; - the app case: only the miss line; - an install that throws: the miss line is still logged; - an uncontained install: nothing is metered or logged.

  • Repository kept: meterEgress now sets repoId when the first holder of a label had none. A test covers it.
  • Behaviour change: the lines are written in finally, so failed, aborted or throwing installs log them too. That includes the check's install fetched … from the registry line, which before was skipped when the install threw. The doc comment and docs/METRICS.md say so.

Not done:

  • Neither real call site is run through an actual cell, because cells need unix sockets, which this sandbox can't bind. Each call site is one call to the tested function.
  • Repositories without a contained install are not counted for the top-repository figure.

To try it: as a site admin, open /settings/capacity, or in the terminal go to About, press c. After a cold contained install, the repository is named next to the registry's bytes for the hour.

Checks run here and passing: bun scripts/gate.ts, bun x tsc --noEmit, bun scripts/design-lint.ts, and bun test on these files:

  • egress-npm-repo
  • egress-admin
  • capacity
  • egress-totals
  • egress-metrics
  • check-install
  • app-install-cache
  • checks

🤖 Generated with Claude Code

Approved

Earlier asks are met. The terminal Egress screen now prints the top repository, read from the same egressHour as the page and MCP, and the egress-admin test asserts it. Both log sites go through the one tested meteredInstall, which also logs on a throw. A later holder no longer loses the repository. The repository id comes from the code that opened the cell, never from install output. The per-repository tally is capped at 256 entries and ages out over the hour. No README change, no new dependency, and the page change is a text span only. Non-blocking: the indentation inside the meteredInstall call in src/checks/service.ts is off by two spaces (the closing lines of the installWithRetry arguments). In src/tui/screens/egress.ts the doc comment runs long. The meterEgress import in src/checks/install.ts sits between node: imports. I could not diff against 7dbcddb02f1e because the clone lacks that commit, so I judged from the full diff. I did not fetch the preview.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs