@bli-cockpit/cli 0.2.290 → 0.2.291

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -67,6 +67,13 @@ export async function collectOneEvidenceFile(collection, options) {
67
67
  markCapApplied(collection, options.kind, "max_file_bytes");
68
68
  return skip("file_too_large");
69
69
  }
70
+ // A zero-byte transcript (a subagent sidecar opened and never written) has nothing to preserve. Staging it made a
71
+ // 0-byte object the uploader refuses with `empty_file` on every tick, forever, and the fleet board read that
72
+ // permanent refusal as a stuck object (RED). Like an empty git diff it is not a gap; the line says it was seen.
73
+ if (read.byteLength === 0) {
74
+ console.error("[raw-evidence] empty transcript not staged, there is nothing in it to preserve", JSON.stringify({ reason: "empty_file", kind: options.kind, byte_size: 0 }));
75
+ return true;
76
+ }
70
77
  let prepared;
71
78
  try {
72
79
  prepared = await prepareTranscriptForUpload(collection, options, names, read.source);
@@ -21,7 +21,7 @@ export async function runCockpitCli(argv, io) {
21
21
  }
22
22
 
23
23
  if (command === "--version" || command === "-V" || command === "version") {
24
- writeLine(io?.stdout ?? process.stdout, "0.2.290");
24
+ writeLine(io?.stdout ?? process.stdout, "0.2.291");
25
25
  return 0;
26
26
  }
27
27
 
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { bookkeepingRead, bookkeepingWrite } from "./bookkeeping-session.js";
6
6
  import { describeError, isMissingFileFailure } from "./health-detail.js";
7
+ import { dropEmptyObjectRecords } from "./raw-evidence-stuck-summary.js";
7
8
  /**
8
9
  * Durable local state for raw-evidence STAGING and DELIVERY ATTEMPTS.
9
10
  *
@@ -29,7 +30,7 @@ import { describeError, isMissingFileFailure } from "./health-detail.js";
29
30
  // BLI-4022. The stuck/held summary moved to its own sibling so this file
30
31
  // stays under the readability band; it is still importable from here,
31
32
  // which is the address every caller already knows.
32
- export { summarizeStuckEvidence, } from "./raw-evidence-stuck-summary.js";
33
+ export { summarizeStuckEvidence } from "./raw-evidence-stuck-summary.js";
33
34
  export const RAW_EVIDENCE_STAGING_FILENAME = "raw-evidence-staging.json";
34
35
  /**
35
36
  * Backoff schedule for an object whose delivery keeps failing.
@@ -75,6 +76,7 @@ async function readStagingFromDisk(stateDir) {
75
76
  const raw = JSON.parse(await fs.readFile(rawEvidenceStagingStatePath(stateDir), "utf8"));
76
77
  const state = parseStagingState(raw);
77
78
  resetStorage403ForEncoding(state);
79
+ dropEmptyObjectRecords(state);
78
80
  return state;
79
81
  }
80
82
  catch (error) {
@@ -72,4 +72,29 @@ function summarizeLiveDeliveryAttempts(entries, ghostCount, now) {
72
72
  held_next_attempt_at: heldNextAttemptAt,
73
73
  held_last_reason: heldOldest?.last_reason ?? null,
74
74
  };
75
+ }
76
+ /**
77
+ * Forget the zero-byte objects an older collector staged. It offered them on every tick and the uploader refused each
78
+ * one with `empty_file`, which no retry can fix, so the fleet board read one as a stuck object for days (RED). The
79
+ * collector no longer stages an empty transcript (`adapters/raw-evidence-transcript-file.ts`); this clears what already
80
+ * sits in the history so the machine stops reporting it. The empty file itself is left for the ordinary staging prune.
81
+ */
82
+ export function dropEmptyObjectRecords(state) {
83
+ let dropped = 0;
84
+ for (const [hash, entry] of Object.entries(state.staged)) {
85
+ if (entry.byte_size !== 0)
86
+ continue;
87
+ delete state.staged[hash];
88
+ dropped += 1;
89
+ }
90
+ for (const [hash, entry] of Object.entries(state.delivery_attempts)) {
91
+ if (entry.last_reason !== "empty_file")
92
+ continue;
93
+ delete state.delivery_attempts[hash];
94
+ dropped += 1;
95
+ }
96
+ if (dropped > 0) {
97
+ console.error("[raw-evidence-staging] empty objects forgotten, nothing in them can be delivered", JSON.stringify({ reason: "empty_file_records_dropped", records_dropped: dropped }));
98
+ }
99
+ return dropped;
75
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.2.290",
3
+ "version": "0.2.291",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {