Skip to content

Artifact GC is reported in four JSON shapes, and the bytesFreed/bytes fields the contract documents are emitted by no command #1257

Description

[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: register comment.

Kind: bug. Source: new finding, register C79. It relates to C33 (#948, contract freshness) and C50 (#893, GC retention).

Problem (main @ a80b89e)

The contract's unified envelope documents three byte counters:

None of them exists in the code. json_envelope::Summary has no byte fields, and PatchEvent has no bytes. The contract's own "GC summary" recipe, repair --json | jq '{removed: .summary.removed, bytesFreed: .summary.bytesFreed, …}' (#L1711-L1718), therefore returns bytesFreed: null. It also returns removed: 1 however many blobs were deleted.

The same GC result is reported four ways, with four key spellings:

Command JSON Bytes freed in JSON
repair one removed event, details: {count, checked} (repair.rs#L769-L780) no. It is computed, then sent only to telemetry (#L212-L217) and the human line
remove removed event, details: {blobsRemoved, rolledBack, archivesRemoved} (remove.rs#L1061-L1068) no. It is printed in human mode only (#L936-L948)
rollback legacy gc: {removedBlobs, removedDiffArchives, removedPackageArchives, bytesFreed} (rollback.rs#L1483-L1488) yes
scan --prune gc: {prunedManifestEntries, removedBlobs, …, bytesFreed} (scan/gc.rs#L96-L106) yes

The PatchAction table's "Emitted by" column has drifted too:

  • discovered lists scan, but only list emits it.
  • downloaded lists get and scan --mode agent, but only repair and update emit it.
  • removed lists rollback, but rollback prints its legacy shape and no events.
  • verified lists scan --dry-run, but scan prints no events.

Proof by execution (debug build at a80b89e, run twice under env -i, same result both times). The fixture is an agent-mode npm project: one applied patch, its before/after blobs, and four unreferenced blob files in .socket/blobs/. repair --offline --json deleted 5 of the 6 blobs. The contract recipe printed {"removed": 1, "bytesFreed": null, "failed": 0}, and the only event was {"action":"removed","details":{"count":5,"checked":6}}. The human run of the same fixture prints Removed 3 unused blobs (38 B freed). remove pkg:npm/left-pad@1.3.0 --json emitted two removed events (the entry, and blobsRemoved: 3), with summary.removed: 1 and no byte count.

Symptoms

None filed. #1066 (rollback counters count only the agent leg) is the same class of counter drift.

Impact

A CI or dashboard that follows the documented recipe gets null and a removal count of 1. The four shapes mean any consumer has to special-case each command. The risk is low, but the documented contract is wrong today, and every new GC caller adds another shape.

Proposed change

  • Add one GcReport { removed_blobs, removed_diff_archives, removed_package_archives, bytes_freed } in json_envelope (or beside ArtifactReferences), serialized identically everywhere. rollback and scan build it instead of their hand-written json! blocks; the keys are unchanged.
  • repair and remove attach it to their artifact-level removed event as additive details keys, keeping count/checked and blobsRemoved/archivesRemoved for compatibility.
  • Either implement summary.bytesFreed (the sum of the removed events' bytes), or delete summary.bytesDownloaded, summary.bytesFreed and events[].bytes from the contract. Fix the jq recipe and the "Emitted by" column to match. Recommendation: implement bytesFreed, which is additive and MINOR; delete bytesDownloaded/downloaded.bytes, because blob downloads don't carry a byte count today and Remove --download-mode and the diff download path (#792) #1049 rewrites that path.
  • Delete the four hand-written GC JSON blocks.

Size and scope

Acceptance criteria

  • repair --json and remove --json report blobs removed and bytes freed under the same keys as rollback/scan --prune.
  • The contract's GC recipe returns a number for bytesFreed (or the recipe is rewritten to the emitted keys), and an e2e test runs the recipe's paths.
  • Every summary and PatchEvent field documented in the contract is serialized by json_envelope. A unit test pins the key set against the contract's schema block.
  • The "Emitted by" column matches the emitters.
  • Existing rollback_duality_invariants and covgap_commands_scan_vendor_flow GC assertions stay green.

Dependencies

Activity

  1. added
    bugSomething isn't working
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    on Oct 9, 2026
  2. added a commit that references this issue on Oct 9, 2026
  3. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged p3 (general CLI JSON contract, no single ecosystem). Not a duplicate: #1066 is the same class of counter drift but a different fix (rollback's top-level counters only count the agent leg), and #948 is the broader contract-freshness tracking issue. No open PR addresses the GC report shape yet. Left open as an actionable bug.


    Generated by Claude Code

  4. added
    v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.
    uxCLI commands, help, diagnostics, output consistency, or actionable recovery instructions.
    compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.
    and removed on Oct 9, 2026
  5. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    v5 release blocker (P1). Align the emitted GC JSON and documented counters before v5 consumers rely on them. A truthful small schema is sufficient; PR #1273 is pending.

    This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.

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

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingcompatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.priority:p1uxCLI commands, help, diagnostics, output consistency, or actionable recovery instructions.v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions