@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.
|
|
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
|
|
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
|
}
|