commit ab9bfa2063bfb6df0b1d8125e9ba1f854eed410b
parent b845ae30867285af38079e67f93e015b1d32b901
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Wed, 30 Sep 2026 09:39:34 -0400
common: doctor applies the drive-health timings (settings.storage.health) before it inspects any drive, as the index and stats bins do, and says which are in force on a "drive health" line (slice DT's Found and left)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
2 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/common/bin/doctor.test.ts b/common/bin/doctor.test.ts
@@ -341,3 +341,25 @@ test("social icons: a refused stored icon is named by file and label, not its ma
assert.ok(!line.detail.includes(secret), "no markup");
assert.ok(report.ok, "a warning, not a failure");
});
+
+// Release 15 slice DT left doctor's line to SG: the drive-health timings are
+// applied before any drive is inspected (as the index and stats bins apply
+// them), and the corpus block says which are in force.
+test("the drive-health timings: applied from settings.storage.health before the corpus is inspected, and printed", async () => {
+ const { healthTimings, applyHealthTimings } = await import("../lib/storageHealth");
+ const c = checkout();
+ mkdirSync(c.paths.channelsDir, { recursive: true });
+ let r = await run(c);
+ assert.equal(
+ r.checks.find((x) => x.id === "drive health")!.detail,
+ "a read may take 3 s, a check every 15 s (3 s each), a stall clears on a clean check twice in a row, 4 reads in flight per drive — the defaults",
+ );
+ writeFileSync(c.paths.settingsFile, JSON.stringify({ storage: { health: { budgetMs: 5000, clearAfterCleanPasses: 3 } } }));
+ r = await run(c);
+ assert.equal(
+ r.checks.find((x) => x.id === "drive health")!.detail,
+ "a read may take 5 s, a check every 15 s (3 s each), a stall clears on a clean check 3 times in a row, 4 reads in flight per drive — settings.storage.health",
+ );
+ assert.equal(healthTimings().budgetMs, 5000, "applied to this process");
+ applyHealthTimings();
+});
diff --git a/common/bin/doctor.ts b/common/bin/doctor.ts
@@ -111,6 +111,22 @@ export async function collectDoctorReport(deps: DoctorDeps): Promise<DoctorRepor
? "no path or binary overrides set (ENVIRONMENT.md lists them)"
: overrides.map((v) => `${v.name}=${env[v.name]}`).join(" "));
+ // The effective settings, read the way every process reads them (defaults
+ // when the file is absent). Read-only: the reader never writes. Read before
+ // the corpus, for the drive-health timings (release 15 slice DT): applied
+ // here, as the index and stats bins apply them, a CLI process's drive
+ // inspects run on the machine's timings instead of racing the defaults.
+ const { settingsFromFile } = await import("../lib/settings");
+ let settings: ReturnType<typeof settingsFromFile> | null = null;
+ let settingsError: Error | null = null;
+ try {
+ settings = settingsFromFile(paths.settingsFile);
+ } catch (err) {
+ settingsError = err as Error;
+ }
+ const { applyHealthTimings } = await import("../lib/storageHealth");
+ const timings = applyHealthTimings(settings?.storage.health);
+
// ── corpus ───────────────────────────────────────────────────────────────
const C = "corpus";
let channelSlugs: string[] = [];
@@ -135,6 +151,12 @@ export async function collectDoctorReport(deps: DoctorDeps): Promise<DoctorRepor
} else if (channelSlugs.length > 0) {
add(C, "media", "ok", "every channel's data/ is reachable");
}
+ const { secondsText, clearRuleText } = await import("../lib/storageHealthTimings");
+ const tuned = Object.keys(settings?.storage.health ?? {}).length > 0;
+ add(C, "drive health", "info",
+ `a read may take ${secondsText(timings.budgetMs)}, a check every ${secondsText(timings.passIntervalMs)} ` +
+ `(${secondsText(timings.probeTimeoutMs)} each), a stall clears on a clean check ${clearRuleText(timings.clearAfterCleanPasses)}, ` +
+ `${timings.inFlightPerLocation} reads in flight per drive — ${tuned ? "settings.storage.health" : "the defaults"}`);
const index = statOrNull(paths.lmdbPath);
if (index) {
add(C, "index", "ok", `${paths.lmdbPath} (stat only; built ${index.mtime.toISOString().slice(0, 16).replace("T", " ")})`);
@@ -163,15 +185,7 @@ export async function collectDoctorReport(deps: DoctorDeps): Promise<DoctorRepor
`${paths.settingsFile} is not a JSON object${parsed instanceof Error ? ` (${parsed.message})` : ""} — every process silently reads it as the defaults`);
}
}
- // The effective settings, read the way every process reads them (defaults
- // when the file is absent). Read-only: the reader never writes.
- const { settingsFromFile } = await import("../lib/settings");
- let settings: ReturnType<typeof settingsFromFile> | null = null;
- try {
- settings = settingsFromFile(paths.settingsFile);
- } catch (err) {
- add(S, "schema", "fail", `settings do not load: ${(err as Error).message}`);
- }
+ if (settingsError) add(S, "schema", "fail", `settings do not load: ${settingsError.message}`);
// ── social icons ─────────────────────────────────────────────────────────
// Every stored social link's icon — settings.json, each site.json,