lossless-openclaw-orchestrator 1.1.2 → 1.1.3

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.
package/README.md CHANGED
@@ -14,7 +14,7 @@ safe action without rereading raw transcripts.
14
14
  [![License](https://img.shields.io/badge/license-PolyForm%20Noncommercial-blue)](LICENSE)
15
15
  [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](CONTRIBUTING.md)
16
16
 
17
- [Setup](docs/SETUP.md) · [Contributing](CONTRIBUTING.md) · [Agent Instructions](AGENTS.md) · [Agent Skill](skills/lossless-openclaw-orchestrator/SKILL.md) · [OpenClaw Plugin](docs/OPENCLAW_PLUGIN.md) · [Security](SECURITY.md) · [Code of Conduct](CODE_OF_CONDUCT.md) · [Vision](VISION.md) · [Privacy](docs/PRIVACY.md) · [Claude Boundary](docs/CLAUDE_ADAPTER_BOUNDARY.md) · [Claim Audit](docs/CLAIM_AUDIT.md) · [Release Notes](docs/RELEASE_NOTES_1.1.2.md) · [1.0 Notes](docs/RELEASE_NOTES_1.0.0.md) · [License](LICENSE)
17
+ [Setup](docs/SETUP.md) · [Contributing](CONTRIBUTING.md) · [Agent Instructions](AGENTS.md) · [Agent Skill](skills/lossless-openclaw-orchestrator/SKILL.md) · [OpenClaw Plugin](docs/OPENCLAW_PLUGIN.md) · [Security](SECURITY.md) · [Code of Conduct](CODE_OF_CONDUCT.md) · [Vision](VISION.md) · [Privacy](docs/PRIVACY.md) · [Claude Boundary](docs/CLAUDE_ADAPTER_BOUNDARY.md) · [Claim Audit](docs/CLAIM_AUDIT.md) · [Release Notes](docs/RELEASE_NOTES_1.1.3.md) · [1.0 Notes](docs/RELEASE_NOTES_1.0.0.md) · [License](LICENSE)
18
18
 
19
19
  ## Why It Matters
20
20
 
@@ -16,7 +16,9 @@ import { runOpenClawGatewayLiveControlSmoke } from "./openclaw-live-control-smok
16
16
  import { runOpenClawPostActionRefreshSmoke } from "./openclaw-post-action-refresh-smoke.js";
17
17
  import { createScorecardSweep } from "./scorecard-sweep.js";
18
18
  import { createScenarioSweep } from "./scenario-sweep.js";
19
+ import { createRuntimeProofIssuePacket } from "./runtime-issue-packet.js";
19
20
  import { createOnboardingStatusReport, writeOnboardingStatusReport } from "./onboarding-status.js";
21
+ import { createRuntimeSweepSummary } from "./runtime-sweep-summary.js";
20
22
  import { normalizeReleaseClaimScope } from "./release-claim-scope.js";
21
23
  import { AppServerLiveControlSmokeClient, runLiveControlSmoke } from "./live-control-smoke.js";
22
24
  import { createLocalMacSearchUiShell, REQUIRED_LOCAL_MAC_SEARCH_UI_TOOLS, sampleLocalMacSearchUiShell, writeLocalMacSearchUiEvidence } from "../../local-mac-ui/src/shell.js";
@@ -380,6 +382,18 @@ async function main() {
380
382
  process.exitCode = 1;
381
383
  return;
382
384
  }
385
+ if (command === "runtime" && args[0] === "sweep-summary") {
386
+ if (hasHelpFlag(args.slice(1))) {
387
+ printRuntimeSweepSummaryHelp();
388
+ return;
389
+ }
390
+ const parsed = parseRuntimeSweepSummaryArgs(args.slice(1));
391
+ const report = createRuntimeSweepSummary(parsed);
392
+ console.log(JSON.stringify(report, null, 2));
393
+ if (parsed.strict && (!report.summaryReady || report.claimBoundary.supportedClaimScope === "none"))
394
+ process.exitCode = 1;
395
+ return;
396
+ }
383
397
  if (command === "ui" && args[0] === "local-mac-search") {
384
398
  if (hasHelpFlag(args.slice(1))) {
385
399
  printLocalMacSearchUiHelp();
@@ -456,6 +470,25 @@ async function main() {
456
470
  process.exitCode = 1;
457
471
  return;
458
472
  }
473
+ if (command === "runtime" && args[0] === "issue-packet") {
474
+ if (hasHelpFlag(args.slice(1))) {
475
+ printRuntimeIssuePacketHelp();
476
+ return;
477
+ }
478
+ const parsed = parseRuntimeIssuePacketArgs(args.slice(1));
479
+ const report = createRuntimeProofIssuePacket({
480
+ evidenceDir: parsed.evidenceDir,
481
+ failureReport: parsed.failureReport,
482
+ parentIssue: parsed.parentIssue,
483
+ operatingLoopIssue: parsed.operatingLoopIssue,
484
+ milestone: parsed.milestone,
485
+ now: parsed.now
486
+ });
487
+ console.log(JSON.stringify(report, null, 2));
488
+ if (parsed.strict && !report.issuePacketReady)
489
+ process.exitCode = 1;
490
+ return;
491
+ }
459
492
  if (command === "release" && args[0] === "preflight") {
460
493
  if (hasHelpFlag(args.slice(1))) {
461
494
  printReleasePreflightHelp();
@@ -750,9 +783,11 @@ function mainUsageText() {
750
783
  " loo openclaw live-control-smoke --evidence-dir path --thread-id id [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--message text] [--strict]",
751
784
  " loo openclaw post-action-refresh-smoke --evidence-dir path --thread-id id --live-proof-report path [--openclaw-bin path] [--dev] [--profile name] [--gateway-url ws://127.0.0.1:port] [--token token] [--gateway-timeout-ms ms] [--session-key key] [--query text] [--expand-profile metadata|brief|evidence] [--token-budget n] [--strict]",
752
785
  " loo scorecards sweep --evidence-dir path [--scorecard-dir path] [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--strict]",
786
+ " loo runtime sweep-summary --evidence-dir path --dry-run-scenarios path --runtime-scenarios path --scorecard-sweep path --published-smoke path [--runtime-proof-dir path] [--now iso] [--strict]",
753
787
  " loo ui local-mac-search --evidence-dir path [--sample] [--strict]",
754
788
  " loo eval retrieval --scenario-file path [--evidence-path path] [--strict]",
755
789
  " loo eval scenarios --evidence-dir path [--scenario-dir path] [--runtime-proof-dir path] [--strict]",
790
+ " loo runtime issue-packet --evidence-dir path --failure-report path [--parent-issue #n] [--operating-loop #n] [--milestone name] [--now iso] [--strict]",
756
791
  " loo release preflight [--evidence-dir path] [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--strict]",
757
792
  " loo release bundle --evidence-dir path [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--strict]",
758
793
  " loo release status --evidence-dir path --candidate-sha sha [--claim-scope codex-live-control|codex-read-search-expand-dry-run|codex-working-app-proof] [--approved-live-control-evidence path] [--runtime-proof-dir path] [--npm-publish-approval-evidence path] [--github-release-approval-evidence path] [--github-ci-evidence path] [--codeql-evidence path] [--desktop-gui-required --desktop-gui-approval-evidence path] [--now iso] [--strict]",
@@ -906,6 +941,48 @@ function printScenarioSweepHelp() {
906
941
  " It does not read raw Codex transcripts, run live Codex control, mutate a desktop GUI, publish npm, or create a GitHub Release."
907
942
  ].join("\n"));
908
943
  }
944
+ function printRuntimeIssuePacketHelp() {
945
+ console.log([
946
+ "Usage:",
947
+ " loo runtime issue-packet --evidence-dir path --failure-report path [--parent-issue #n] [--operating-loop #n] [--milestone name] [--now iso] [--strict]",
948
+ "",
949
+ "Writes a public-safe issue-ready handoff packet from a failed runtime proof or scenario sweep report.",
950
+ "",
951
+ "Required:",
952
+ " --evidence-dir is required and receives runtime-proof-issue-packet.json.",
953
+ " --failure-report points to the failed public-safe runtime proof, smoke, or scenario-sweep JSON report.",
954
+ "",
955
+ "Strict mode:",
956
+ " --strict exits non-zero when the failure report is missing, malformed, lacks blocker codes, or when packet redaction fails.",
957
+ "",
958
+ "Safety boundary:",
959
+ " The command never runs gh issue create and never writes to GitHub.",
960
+ " It records only blocker codes, scenario ids, duplicate-check query, acceptance criteria, proof boundary, and redaction categories.",
961
+ " It does not read raw Codex transcripts, run live Codex control, mutate a GUI, publish npm, or create a GitHub Release."
962
+ ].join("\n"));
963
+ }
964
+ function printRuntimeSweepSummaryHelp() {
965
+ console.log([
966
+ "Usage:",
967
+ " loo runtime sweep-summary --evidence-dir path --dry-run-scenarios path --runtime-scenarios path --scorecard-sweep path --published-smoke path [--runtime-proof-dir path] [--now iso] [--strict]",
968
+ "",
969
+ "Writes a public-safe summary that separates dry-run scenario readiness from missing runtime proof markers.",
970
+ "",
971
+ "Required:",
972
+ " --dry-run-scenarios points to the v1 dry-run scenario sweep report.",
973
+ " --runtime-scenarios points to the v1.1 runtime-required scenario sweep report.",
974
+ " --scorecard-sweep points to the working-app scorecard sweep report.",
975
+ " --published-smoke points to the published-package or gateway setup smoke report.",
976
+ "",
977
+ "Strict mode:",
978
+ " --strict exits non-zero when the summary itself cannot be produced safely or no claim scope is supported.",
979
+ " Missing runtime markers remain claim-boundary blockers, not packet-generation failures.",
980
+ "",
981
+ "Safety boundary:",
982
+ " The command consumes public-safe reports only.",
983
+ " It does not read raw Codex transcripts, run live Codex control, mutate a GUI, publish npm, create tags, or create a GitHub Release."
984
+ ].join("\n"));
985
+ }
909
986
  function printOnboardingStatusHelp() {
910
987
  console.log([
911
988
  "Usage:",
@@ -1640,6 +1717,47 @@ function parseScenarioSweepArgs(input) {
1640
1717
  throw new Error("eval scenarios requires --evidence-dir");
1641
1718
  return { evidenceDir, scenarioDir, runtimeProofDir, scenarioIds: scenarioIds.length ? scenarioIds : undefined, strict };
1642
1719
  }
1720
+ function parseRuntimeIssuePacketArgs(input) {
1721
+ let evidenceDir = "";
1722
+ let failureReport = "";
1723
+ let parentIssue;
1724
+ let operatingLoopIssue;
1725
+ let milestone;
1726
+ let now;
1727
+ let strict = false;
1728
+ for (let index = 0; index < input.length; index += 1) {
1729
+ const arg = input[index];
1730
+ if (arg === "--evidence-dir") {
1731
+ evidenceDir = requireOptionValue(input[++index], arg);
1732
+ }
1733
+ else if (arg === "--failure-report") {
1734
+ failureReport = requireOptionValue(input[++index], arg);
1735
+ }
1736
+ else if (arg === "--parent-issue") {
1737
+ parentIssue = requireOptionValue(input[++index], arg);
1738
+ }
1739
+ else if (arg === "--operating-loop") {
1740
+ operatingLoopIssue = requireOptionValue(input[++index], arg);
1741
+ }
1742
+ else if (arg === "--milestone") {
1743
+ milestone = requireOptionValue(input[++index], arg);
1744
+ }
1745
+ else if (arg === "--now") {
1746
+ now = requireOptionValue(input[++index], arg);
1747
+ }
1748
+ else if (arg === "--strict") {
1749
+ strict = true;
1750
+ }
1751
+ else {
1752
+ throw new Error(`Unknown runtime issue-packet option: ${arg}`);
1753
+ }
1754
+ }
1755
+ if (!evidenceDir)
1756
+ throw new Error("runtime issue-packet requires --evidence-dir");
1757
+ if (!failureReport)
1758
+ throw new Error("runtime issue-packet requires --failure-report");
1759
+ return { evidenceDir, failureReport, parentIssue, operatingLoopIssue, milestone, now, strict };
1760
+ }
1643
1761
  function readRetrievalScenarioFile(path) {
1644
1762
  const scenarioPath = resolve(path);
1645
1763
  if (!existsSync(scenarioPath))
@@ -2066,6 +2184,57 @@ function parseScorecardSweepArgs(input) {
2066
2184
  throw new Error("scorecards sweep requires --evidence-dir");
2067
2185
  return { evidenceDir, scorecardDir, claimScope, strict };
2068
2186
  }
2187
+ function parseRuntimeSweepSummaryArgs(input) {
2188
+ let evidenceDir;
2189
+ let dryRunScenarios;
2190
+ let runtimeScenarios;
2191
+ let scorecardSweep;
2192
+ let publishedSmoke;
2193
+ let runtimeProofDir;
2194
+ let now;
2195
+ let strict = false;
2196
+ for (let index = 0; index < input.length; index += 1) {
2197
+ const arg = input[index];
2198
+ if (arg === "--evidence-dir") {
2199
+ evidenceDir = requireOptionValue(input[++index], arg);
2200
+ }
2201
+ else if (arg === "--dry-run-scenarios") {
2202
+ dryRunScenarios = requireOptionValue(input[++index], arg);
2203
+ }
2204
+ else if (arg === "--runtime-scenarios") {
2205
+ runtimeScenarios = requireOptionValue(input[++index], arg);
2206
+ }
2207
+ else if (arg === "--scorecard-sweep") {
2208
+ scorecardSweep = requireOptionValue(input[++index], arg);
2209
+ }
2210
+ else if (arg === "--published-smoke") {
2211
+ publishedSmoke = requireOptionValue(input[++index], arg);
2212
+ }
2213
+ else if (arg === "--runtime-proof-dir") {
2214
+ runtimeProofDir = requireOptionValue(input[++index], arg);
2215
+ }
2216
+ else if (arg === "--now") {
2217
+ now = requireOptionValue(input[++index], arg);
2218
+ }
2219
+ else if (arg === "--strict") {
2220
+ strict = true;
2221
+ }
2222
+ else {
2223
+ throw new Error(`Unknown runtime sweep-summary option: ${arg}`);
2224
+ }
2225
+ }
2226
+ if (!evidenceDir)
2227
+ throw new Error("runtime sweep-summary requires --evidence-dir");
2228
+ if (!dryRunScenarios)
2229
+ throw new Error("runtime sweep-summary requires --dry-run-scenarios");
2230
+ if (!runtimeScenarios)
2231
+ throw new Error("runtime sweep-summary requires --runtime-scenarios");
2232
+ if (!scorecardSweep)
2233
+ throw new Error("runtime sweep-summary requires --scorecard-sweep");
2234
+ if (!publishedSmoke)
2235
+ throw new Error("runtime sweep-summary requires --published-smoke");
2236
+ return { evidenceDir, dryRunScenarios, runtimeScenarios, scorecardSweep, publishedSmoke, runtimeProofDir, now, strict };
2237
+ }
2069
2238
  function parsePositiveInteger(value, name, max) {
2070
2239
  const parsed = Number(value);
2071
2240
  if (!Number.isInteger(parsed) || parsed < 1 || (max !== undefined && parsed > max)) {
@@ -0,0 +1,357 @@
1
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
+ const DEFAULT_LABELS = ["enhancement", "safety", "orchestrator", "eval"];
4
+ const DEFAULT_PARENT_REFS = ["#309", "#16"];
5
+ const SECRET_LIKE_PATTERN = /(npm_[A-Za-z0-9]{20,}|Bearer\s+[A-Za-z0-9._-]{20,}|sk-[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|gh[pousr]_[A-Za-z0-9_]{20,}|-----BEGIN [A-Z ]*PRIVATE KEY-----)/g;
6
+ const RAW_TRANSCRIPT_PATH_PATTERN = /(?:~|\/[^\s"'`]*)\/\.codex\/(?:sessions|archived_sessions)\/[^\s"'`]+|\b[\w.-]+\.jsonl(?:\.gz)?\b/g;
7
+ const SQLITE_ARTIFACT_PATTERN = /\b[\w.-]+\.(?:sqlite|sqlite-wal|sqlite-shm|db|db-journal|db-wal|db-shm)\b/g;
8
+ const SCREENSHOT_PATTERN = /\b[\w.-]+\.(?:png|jpg|jpeg|webp|heic|gif|tiff|mov|mp4|m4v|webm)\b/gi;
9
+ export function createRuntimeProofIssuePacket(options) {
10
+ const evidenceDir = resolve(options.evidenceDir);
11
+ const failureReportPath = resolve(options.failureReport);
12
+ const evidenceDirRejected = hasPrivateFinding(evidenceDir, "raw_transcript_path");
13
+ const packetPath = evidenceDirRejected ? "not_written:evidence_dir_transcript_path_rejected" : join(evidenceDir, "runtime-proof-issue-packet.json");
14
+ if (!evidenceDirRejected)
15
+ mkdirSync(evidenceDir, { recursive: true });
16
+ const generatedAtResult = normalizeGeneratedAt(options.now);
17
+ const generatedAt = generatedAtResult.value;
18
+ const explicitParentRefs = [
19
+ normalizeIssueRef(options.parentIssue),
20
+ normalizeIssueRef(options.operatingLoopIssue)
21
+ ].filter(Boolean);
22
+ const parentRefs = uniqueStrings(explicitParentRefs.length > 0 ? explicitParentRefs : DEFAULT_PARENT_REFS);
23
+ const sourceMissing = !existsSync(failureReportPath);
24
+ const resolvedFailureReportPath = sourceMissing ? failureReportPath : safeRealpath(failureReportPath);
25
+ const transcriptPathRejected = !sourceMissing && (hasPrivateFinding(failureReportPath, "raw_transcript_path") ||
26
+ hasPrivateFinding(resolvedFailureReportPath, "raw_transcript_path"));
27
+ const sourceText = !sourceMissing && !transcriptPathRejected ? readFileSync(resolvedFailureReportPath, "utf8") : "";
28
+ const inputFindings = scanTextForPrivateFindings(sourceText);
29
+ const parsed = readJsonObject(sourceText);
30
+ const invalidJson = !sourceMissing && !transcriptPathRejected && !parsed;
31
+ const blockerCodes = sourceMissing
32
+ ? ["failure_report_missing"]
33
+ : transcriptPathRejected
34
+ ? ["failure_report_transcript_path_rejected"]
35
+ : parsed
36
+ ? extractBlockerCodes(parsed)
37
+ : ["failure_report_invalid_json"];
38
+ const scenarioIds = parsed ? extractScenarioIds(parsed) : [];
39
+ const rawClaimScope = parsed ? stringField(parsed, "claimScope") ?? stringField(parsed, "claim_scope") : null;
40
+ const claimScope = rawClaimScope ? safePublicCode(rawClaimScope) : null;
41
+ const primaryBlocker = blockerCodes[0] ?? "runtime_proof_failure";
42
+ const title = `Runtime proof failed: ${safeTitleSegment(primaryBlocker)}`;
43
+ const labels = uniqueStrings([
44
+ ...DEFAULT_LABELS,
45
+ ...(scenarioIds.some((id) => /codex|gateway|desktop/i.test(id)) || blockerCodes.some((blocker) => /codex|gateway|desktop/i.test(blocker)) ? ["codex"] : [])
46
+ ]);
47
+ const duplicateCheckQuery = buildDuplicateCheckQuery(title, primaryBlocker);
48
+ const evidencePath = publicEvidencePath(evidenceDir);
49
+ const steps = [
50
+ "Run the relevant LCO runtime proof or scenario sweep with a public-safe evidence directory.",
51
+ "Inspect the sanitized failure report and blocker codes.",
52
+ "Open or update a GitHub issue only after duplicate-check review and maintainer approval.",
53
+ "Attach public-safe evidence links only; do not paste raw gateway output, raw prompts, raw transcripts, screenshots, SQLite DB contents, tokens, cookies, or credentials."
54
+ ];
55
+ const expected = "Runtime proof markers satisfy the claimed scenario, or the failure is converted into a public-safe issue handoff with exact blocker codes and acceptance criteria.";
56
+ const actual = sourceMissing
57
+ ? "No failure report was available for packet generation."
58
+ : transcriptPathRejected
59
+ ? "The failure report path looked like a raw Codex transcript path and was rejected before reading."
60
+ : invalidJson
61
+ ? "The failure report was not valid JSON; only sanitized category-level findings were retained."
62
+ : `Runtime proof failed with blocker codes: ${blockerCodes.join(", ") || "none reported"}.`;
63
+ const acceptanceCriteria = [
64
+ "Reproduce the failed runtime proof or scenario sweep from the public-safe command and evidence path.",
65
+ "Resolve or explicitly defer each blocker code listed in this packet.",
66
+ "Record a new public-safe proof marker or a new fail-closed issue packet after the fix.",
67
+ "Keep external GitHub writes manual or approval-gated; this packet alone must not create issues.",
68
+ "Verify the final packet contains no raw transcript text, raw transcript paths, screenshots, SQLite DBs, tokens, cookies, credentials, or private customer data."
69
+ ];
70
+ const proofBoundary = "This packet is a public-safe GitHub issue handoff for failed runtime proof only. It does not create GitHub issues, mutate external systems, run live Codex control, mutate a GUI, publish npm, or create a GitHub Release.";
71
+ const issueBody = buildIssueBody({
72
+ parentRefs,
73
+ evidencePath,
74
+ scenarioIds,
75
+ blockerCodes,
76
+ steps,
77
+ expected,
78
+ actual,
79
+ proofBoundary,
80
+ acceptanceCriteria,
81
+ duplicateCheckQuery
82
+ });
83
+ const initialReport = {
84
+ kind: "loo_runtime_proof_issue_packet",
85
+ ok: false,
86
+ issuePacketReady: false,
87
+ generatedAt,
88
+ packetPath,
89
+ title,
90
+ labels,
91
+ milestone: options.milestone?.trim() || null,
92
+ parentRefs,
93
+ duplicateCheckQuery,
94
+ steps,
95
+ expected,
96
+ actual,
97
+ proofBoundary,
98
+ acceptanceCriteria,
99
+ evidencePath,
100
+ issueBody,
101
+ source: {
102
+ failureReportPath: redactPrivateSpans(failureReportPath),
103
+ claimScope,
104
+ scenarioIds,
105
+ blockerCodes,
106
+ inputFindings
107
+ },
108
+ redactionScan: {
109
+ publicSafe: true,
110
+ rawSecretIncluded: false,
111
+ rawTranscriptPathIncluded: false,
112
+ sqliteIncluded: false,
113
+ screenshotOrVideoIncluded: false,
114
+ findings: []
115
+ },
116
+ actionsPerformed: {
117
+ githubIssueCreated: false,
118
+ externalWrite: false,
119
+ liveCodexControlRun: false,
120
+ desktopGuiActionRun: false,
121
+ rawTranscriptRead: false
122
+ },
123
+ privateDataExclusions: [
124
+ "raw gateway output",
125
+ "raw Codex transcripts",
126
+ "raw prompts or transcript spans",
127
+ "absolute transcript paths",
128
+ "SQLite DBs",
129
+ "screenshots or videos",
130
+ "tokens, credentials, API keys, cookies",
131
+ "private customer data"
132
+ ],
133
+ blockers: [
134
+ ...(evidenceDirRejected ? ["evidence_dir_transcript_path_rejected"] : []),
135
+ ...(generatedAtResult.invalid ? ["invalid_generated_at"] : []),
136
+ ...(sourceMissing ? ["failure_report_missing"] : []),
137
+ ...(transcriptPathRejected ? ["failure_report_transcript_path_rejected"] : []),
138
+ ...(invalidJson ? ["failure_report_invalid_json"] : []),
139
+ ...(!sourceMissing && !transcriptPathRejected && !invalidJson && blockerCodes.length === 0 ? ["failure_report_blockers_missing"] : [])
140
+ ],
141
+ nextAction: ""
142
+ };
143
+ const outputFindings = scanTextForPrivateFindings(JSON.stringify(initialReport));
144
+ const redactionScan = {
145
+ publicSafe: outputFindings.length === 0,
146
+ rawSecretIncluded: outputFindings.some((finding) => finding.reason === "secret_like_value"),
147
+ rawTranscriptPathIncluded: outputFindings.some((finding) => finding.reason === "raw_transcript_path"),
148
+ sqliteIncluded: outputFindings.some((finding) => finding.reason === "sqlite_artifact"),
149
+ screenshotOrVideoIncluded: outputFindings.some((finding) => finding.reason === "screenshot_or_video"),
150
+ findings: outputFindings
151
+ };
152
+ const blockers = [
153
+ ...initialReport.blockers,
154
+ ...(redactionScan.publicSafe ? [] : ["issue_packet_redaction_failed"])
155
+ ];
156
+ const report = {
157
+ ...initialReport,
158
+ ok: blockers.length === 0,
159
+ issuePacketReady: blockers.length === 0,
160
+ redactionScan,
161
+ blockers,
162
+ nextAction: blockers.length === 0
163
+ ? "Review the duplicate-check query, then manually create or update the GitHub issue with this public-safe packet."
164
+ : "Repair the failure report input or packet redaction blockers before filing an issue."
165
+ };
166
+ const persistedReport = redactionScan.publicSafe ? report : createRedactionFailureStub(report, redactionScan, blockers);
167
+ if (!evidenceDirRejected)
168
+ writeFileSync(packetPath, `${JSON.stringify(persistedReport, null, 2)}\n`);
169
+ return persistedReport;
170
+ }
171
+ function readJsonObject(text) {
172
+ try {
173
+ const parsed = JSON.parse(text);
174
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
175
+ }
176
+ catch {
177
+ return null;
178
+ }
179
+ }
180
+ function normalizeGeneratedAt(value) {
181
+ if (!value)
182
+ return { value: new Date().toISOString(), invalid: false };
183
+ const parsed = new Date(value);
184
+ if (!Number.isFinite(parsed.getTime()))
185
+ return { value: new Date().toISOString(), invalid: true };
186
+ const normalized = parsed.toISOString();
187
+ return { value: normalized, invalid: normalized !== value };
188
+ }
189
+ function publicEvidencePath(evidenceDir) {
190
+ return `local-evidence-dir:${safeCode(basename(evidenceDir) || "evidence")}`;
191
+ }
192
+ function safeRealpath(path) {
193
+ try {
194
+ return realpathSync(path);
195
+ }
196
+ catch {
197
+ return path;
198
+ }
199
+ }
200
+ function createRedactionFailureStub(report, redactionScan, blockers) {
201
+ return {
202
+ ...report,
203
+ ok: false,
204
+ issuePacketReady: false,
205
+ title: "Runtime proof packet redaction failed",
206
+ milestone: null,
207
+ duplicateCheckQuery: "",
208
+ steps: [],
209
+ expected: "A runtime proof issue packet must be public-safe before it is persisted.",
210
+ actual: "The generated packet failed its final redaction scan; unsafe fields were replaced by this minimal fail-closed stub.",
211
+ acceptanceCriteria: [],
212
+ issueBody: "",
213
+ source: {
214
+ failureReportPath: redactPrivateSpans(report.source.failureReportPath),
215
+ claimScope: null,
216
+ scenarioIds: [],
217
+ blockerCodes: [],
218
+ inputFindings: report.source.inputFindings
219
+ },
220
+ redactionScan,
221
+ blockers,
222
+ nextAction: "Repair the failure report input or packet redaction blockers before filing an issue."
223
+ };
224
+ }
225
+ function scanTextForPrivateFindings(text) {
226
+ return [
227
+ countFinding("secret_like_value", text.match(SECRET_LIKE_PATTERN)?.length ?? 0),
228
+ countFinding("raw_transcript_path", text.match(RAW_TRANSCRIPT_PATH_PATTERN)?.length ?? 0),
229
+ countFinding("sqlite_artifact", text.match(SQLITE_ARTIFACT_PATTERN)?.length ?? 0),
230
+ countFinding("screenshot_or_video", text.match(SCREENSHOT_PATTERN)?.length ?? 0)
231
+ ].filter((finding) => Boolean(finding));
232
+ }
233
+ function hasPrivateFinding(text, reason) {
234
+ return scanTextForPrivateFindings(text).some((finding) => finding.reason === reason);
235
+ }
236
+ function countFinding(reason, count) {
237
+ return count > 0 ? { reason, count } : null;
238
+ }
239
+ function extractBlockerCodes(report) {
240
+ return uniqueStrings([
241
+ ...stringArrayField(report, "blockers"),
242
+ ...stringArrayField(report, "setupBlockers"),
243
+ ...stringArrayField(report, "rawEvidenceBlockers"),
244
+ ...extractScenarioBlockers(report),
245
+ stringField(report, "blocker")
246
+ ].filter(Boolean)).map((blocker) => safePublicCode(blocker));
247
+ }
248
+ function extractScenarioBlockers(report) {
249
+ const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
250
+ return scenarios.flatMap((scenario) => {
251
+ if (!scenario || typeof scenario !== "object" || Array.isArray(scenario))
252
+ return [];
253
+ return stringArrayField(scenario, "blockers");
254
+ });
255
+ }
256
+ function extractScenarioIds(report) {
257
+ const scenarios = Array.isArray(report.scenarios) ? report.scenarios : [];
258
+ return uniqueStrings([
259
+ stringField(report, "scenario_id"),
260
+ stringField(report, "scenarioId"),
261
+ stringField(report, "id"),
262
+ ...scenarios.flatMap((scenario) => {
263
+ if (!scenario || typeof scenario !== "object" || Array.isArray(scenario))
264
+ return [];
265
+ return [
266
+ stringField(scenario, "id"),
267
+ stringField(scenario, "scenario_id"),
268
+ stringField(scenario, "scenarioId")
269
+ ];
270
+ })
271
+ ].filter(Boolean)).map((id) => safePublicCode(id));
272
+ }
273
+ function buildDuplicateCheckQuery(title, primaryBlocker) {
274
+ return `repo:100yenadmin/Lossless-Codex-Orchestrator-LCO is:issue is:open "${safeQueryPhrase(primaryBlocker)}" "${safeQueryPhrase(title)}"`;
275
+ }
276
+ function buildIssueBody(input) {
277
+ return [
278
+ `Parent: ${input.parentRefs.join(" / ")}`,
279
+ "",
280
+ "## Summary",
281
+ "",
282
+ "A runtime proof or scenario sweep failed and has been converted into a public-safe issue handoff packet.",
283
+ "",
284
+ "## Duplicate Check",
285
+ "",
286
+ `- Query: \`${input.duplicateCheckQuery}\``,
287
+ "",
288
+ "## Evidence",
289
+ "",
290
+ `- Evidence path: \`${input.evidencePath}\``,
291
+ `- Scenario ids: ${input.scenarioIds.length > 0 ? input.scenarioIds.map((id) => `\`${id}\``).join(", ") : "`unknown`"}`,
292
+ `- Blockers: ${input.blockerCodes.length > 0 ? input.blockerCodes.map((code) => `\`${code}\``).join(", ") : "`none reported`"}`,
293
+ "",
294
+ "## Steps",
295
+ "",
296
+ ...input.steps.map((step) => `- ${step}`),
297
+ "",
298
+ "## Expected",
299
+ "",
300
+ input.expected,
301
+ "",
302
+ "## Actual",
303
+ "",
304
+ input.actual,
305
+ "",
306
+ "## Acceptance Criteria",
307
+ "",
308
+ ...input.acceptanceCriteria.map((criterion) => `- ${criterion}`),
309
+ "",
310
+ "## Proof Boundary",
311
+ "",
312
+ input.proofBoundary,
313
+ ""
314
+ ].join("\n");
315
+ }
316
+ function stringField(record, field) {
317
+ const value = record?.[field];
318
+ return typeof value === "string" && value.trim() ? value.trim() : null;
319
+ }
320
+ function stringArrayField(record, field) {
321
+ const value = record[field];
322
+ if (!Array.isArray(value))
323
+ return [];
324
+ return value.filter((entry) => typeof entry === "string" && Boolean(entry.trim())).map((entry) => entry.trim());
325
+ }
326
+ function normalizeIssueRef(value) {
327
+ if (!value)
328
+ return null;
329
+ const trimmed = value.trim();
330
+ if (/^#\d+$/.test(trimmed))
331
+ return trimmed;
332
+ if (/^\d+$/.test(trimmed))
333
+ return `#${trimmed}`;
334
+ return null;
335
+ }
336
+ function uniqueStrings(values) {
337
+ return [...new Set(values.filter(Boolean))];
338
+ }
339
+ function safeCode(value) {
340
+ return value.replace(/[^A-Za-z0-9_:#./-]/g, "_").slice(0, 180);
341
+ }
342
+ function safePublicCode(value) {
343
+ return safeCode(redactPrivateSpans(value));
344
+ }
345
+ function safeTitleSegment(value) {
346
+ return safeCode(value).replace(/_/g, " ").slice(0, 120).trim() || "runtime proof failure";
347
+ }
348
+ function safeQueryPhrase(value) {
349
+ return redactPrivateSpans(value).replace(/["`$\\]/g, "").slice(0, 140);
350
+ }
351
+ function redactPrivateSpans(value) {
352
+ return value
353
+ .replace(SECRET_LIKE_PATTERN, "redacted_secret_like_value")
354
+ .replace(RAW_TRANSCRIPT_PATH_PATTERN, "redacted_raw_transcript_path")
355
+ .replace(SQLITE_ARTIFACT_PATTERN, "redacted_sqlite_artifact")
356
+ .replace(SCREENSHOT_PATTERN, "redacted_media_artifact");
357
+ }