fix: warn on ad hoc web-probe scripts

This commit is contained in:
Codex
2026-06-26 09:45:30 +00:00
parent 2a8f279575
commit 61d618f97b
4 changed files with 93 additions and 0 deletions
+1
View File
@@ -63,6 +63,7 @@ export function hwlabNodeWebProbeHelp(): Record<string, unknown> {
},
notes: [
"Default URL, browser proxy mode, observe/analyze thresholds, and project-management command allowlist come from config/hwlab-node-lanes.yaml webProbe.",
"`web-probe script` is an ad-hoc exploration escape hatch; repeated/high-frequency workflows must become `web-probe observe command` types or repo-owned web-probe commands.",
"observe is passive by default; user actions must be explicit observe command entries in control.jsonl.",
"After observe start, prefer observe status|command|stop|collect|analyze <id> instead of repeating --node/--lane/--state-dir.",
"collect views render bounded summaries from existing artifacts and do not create a second source of truth.",
@@ -0,0 +1,40 @@
import assert from "node:assert/strict";
import { test } from "bun:test";
import { renderWebProbeScriptResult } from "./web-observe-render";
test("web-probe script render warns to promote repeated scripts into commands", () => {
const rendered = renderWebProbeScriptResult({
ok: true,
status: "pass",
command: "web-probe script --node D601 --lane v03",
node: "D601",
lane: "v03",
url: "https://hwlab.example.test",
warnings: [{
code: "web_probe_script_ad_hoc_only",
severity: "warning",
message: "web-probe script is for one-off exploration; repeated or high-frequency checks must be promoted to a typed command instead of rerunning temporary scripts.",
}],
hints: [
"Prefer `web-probe observe start` plus `web-probe observe command` for interactive flows.",
],
preferredCommands: {
startObserver: "bun scripts/cli.ts web-probe observe start --node D601 --lane v03 --target-path /projects/mdtodo",
mdtodoSummary: "bun scripts/cli.ts web-probe observe collect <observerId> --view project-mdtodo-summary",
},
summary: { ok: true, status: "pass" },
issueEvidence: {},
probe: { steps: [], script: { result: { ok: true } } },
reportLoad: { source: "stdout", path: ".state/web-probe-script/run.demo/web-probe-script-report.json" },
result: { exitCode: 0, timedOut: false },
});
const text = String(rendered.renderedText ?? "");
assert.match(text, /WARNINGS/u);
assert.match(text, /web_probe_script_ad_hoc_only/u);
assert.match(text, /HINTS/u);
assert.match(text, /web-probe observe command/u);
assert.match(text, /startObserver: bun scripts\/cli\.ts web-probe observe start/u);
assert.match(text, /mdtodoSummary: bun scripts\/cli\.ts web-probe observe collect/u);
});
@@ -1413,6 +1413,9 @@ export function renderWebProbeScriptResult(result: Record<string, unknown>): Rec
const recoveredArtifactSummary = record(recoveredArtifacts.artifacts);
const recoveredItems = webObserveArray(recoveredArtifactSummary.items).slice(-8).map((item) => record(item));
const steps = webObserveArray(probe.steps).slice(-5).map((item) => record(item));
const warnings = webObserveArray(result.warnings).slice(0, 6);
const hints = webObserveArray(result.hints).slice(0, 6).map((item) => String(item ?? "").trim()).filter(Boolean);
const preferredCommands = record(result.preferredCommands);
const resultRows = webProbeScriptRecordRows(scriptResult, 12);
const evidenceRows = webProbeScriptRecordRows(issueEvidence, 12);
const summaryRows = [
@@ -1462,9 +1465,27 @@ export function renderWebProbeScriptResult(result: Record<string, unknown>): Rec
recoveredItems.map((item) => [item.kind, item.byteCount, item.path]),
),
"",
warnings.length === 0
? "WARNINGS\n-"
: [
"WARNINGS",
webObserveTable(
["CODE", "SEVERITY", "MESSAGE"],
warnings.map((item) => {
const warning = record(item);
return [warning.code ?? "warning", warning.severity ?? warning.level ?? "warning", warning.message ?? warning.summary ?? webProbeScriptPreview(warning)];
}),
),
].join("\n"),
"",
hints.length === 0
? "HINTS\n-"
: ["HINTS", ...hints.map((hint) => `- ${hint}`)].join("\n"),
"",
"NEXT",
` report: ${reportLoad.path ?? probe.reportPath ?? "-"}`,
` rerun: ${result.command ?? `web-probe script --node ${result.node ?? "-"} --lane ${result.lane ?? "-"}`}`,
...Object.entries(preferredCommands).map(([name, command]) => ` ${name}: ${String(command)}`),
].join("\n");
return withWebObserveRendered(result, renderedText);
}
@@ -558,6 +558,9 @@ export function runNodeWebProbeScript(
degradedReason: recoveredReport.degradedReason,
result: recoveredReport.result === null ? null : compactCommandResultRedacted(recoveredReport.result, [material.password ?? ""]),
},
warnings: webProbeScriptGovernanceWarnings(options),
hints: webProbeScriptGovernanceHints(options),
preferredCommands: webProbeScriptPreferredCommands(options),
recoveredArtifacts: recoveredArtifacts === null ? null : {
source: recoveredArtifacts.source,
degradedReason: recoveredArtifacts.degradedReason,
@@ -569,6 +572,34 @@ export function runNodeWebProbeScript(
});
}
function webProbeScriptGovernanceWarnings(options: NodeWebProbeScriptOptions): Record<string, unknown>[] {
return [{
code: "web_probe_script_ad_hoc_only",
severity: "warning",
message: "web-probe script is for one-off exploration; repeated or high-frequency checks must be promoted to a typed command instead of rerunning temporary scripts.",
node: options.node,
lane: options.lane,
valuesRedacted: true,
}];
}
function webProbeScriptGovernanceHints(options: NodeWebProbeScriptOptions): string[] {
return [
"Prefer `web-probe observe start` plus `web-probe observe command` for interactive flows; use `observe collect/analyze` for repeated evidence reads.",
"If the same script is needed more than once, add or extend a reusable command type in the web-probe observe command surface.",
`For this target, start with: bun scripts/cli.ts web-probe observe start --node ${options.node} --lane ${options.lane} --target-path /projects/mdtodo`,
];
}
function webProbeScriptPreferredCommands(options: NodeWebProbeScriptOptions): Record<string, string> {
return {
startObserver: `bun scripts/cli.ts web-probe observe start --node ${options.node} --lane ${options.lane} --target-path /projects/mdtodo`,
mdtodoSummary: "bun scripts/cli.ts web-probe observe collect <observerId> --view project-mdtodo-summary",
analyze: "bun scripts/cli.ts web-probe observe analyze <observerId>",
addCommandType: "Add a repo-owned web-probe observe command type before repeating this script.",
};
}
export function nodeWebProbeScriptRemoteShell(options: NodeWebProbeScriptOptions, secretSpec: RuntimeSecretSpec, password: string, webProbeProxy: NodeWebProbeHostProxyEnv): string {
const userScriptB64 = Buffer.from(options.scriptText, "utf8").toString("base64");
const runnerB64 = Buffer.from(nodeWebProbeScriptRunnerSource(), "utf8").toString("base64");