omnius 1.0.570 → 1.0.572

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/dist/index.js CHANGED
@@ -327301,9 +327301,9 @@ ${lanes.join("\n")}
327301
327301
  }
327302
327302
  return flatten2(results);
327303
327303
  function visitDirectory(path22, absolutePath, depth2) {
327304
- const canonicalPath = toCanonical(realpath(absolutePath));
327305
- if (visited.has(canonicalPath)) return;
327306
- visited.set(canonicalPath, true);
327304
+ const canonicalPath2 = toCanonical(realpath(absolutePath));
327305
+ if (visited.has(canonicalPath2)) return;
327306
+ visited.set(canonicalPath2, true);
327307
327307
  const { files, directories } = getFileSystemEntries(path22);
327308
327308
  for (const current of toSorted(files, compareStringsCaseSensitive)) {
327309
327309
  const name10 = combinePaths(path22, current);
@@ -505227,13 +505227,13 @@ ${options2.prefix}` : "\n" : options2.prefix
505227
505227
  if (!this.typingWatchers) this.typingWatchers = /* @__PURE__ */ new Map();
505228
505228
  this.typingWatchers.isInvoked = false;
505229
505229
  const createProjectWatcher = (path16, typingsWatcherType) => {
505230
- const canonicalPath = this.toPath(path16);
505231
- toRemove.delete(canonicalPath);
505232
- if (!this.typingWatchers.has(canonicalPath)) {
505230
+ const canonicalPath2 = this.toPath(path16);
505231
+ toRemove.delete(canonicalPath2);
505232
+ if (!this.typingWatchers.has(canonicalPath2)) {
505233
505233
  const watchType = typingsWatcherType === "FileWatcher" ? WatchType.TypingInstallerLocationFile : WatchType.TypingInstallerLocationDirectory;
505234
505234
  this.typingWatchers.set(
505235
- canonicalPath,
505236
- canWatchDirectoryOrFilePath(canonicalPath) ? typingsWatcherType === "FileWatcher" ? this.projectService.watchFactory.watchFile(
505235
+ canonicalPath2,
505236
+ canWatchDirectoryOrFilePath(canonicalPath2) ? typingsWatcherType === "FileWatcher" ? this.projectService.watchFactory.watchFile(
505237
505237
  path16,
505238
505238
  () => !this.typingWatchers.isInvoked ? this.onTypingInstallerWatchInvoke() : this.writeLog(`TypingWatchers already invoked`),
505239
505239
  2e3,
@@ -508521,8 +508521,8 @@ ${options2.prefix}` : "\n" : options2.prefix
508521
508521
  var _a22;
508522
508522
  cleanExtendedConfigCache(this.extendedConfigCache, extendedConfigFilePath, (fileName) => this.toPath(fileName));
508523
508523
  let ensureProjectsForOpenFiles = false;
508524
- (_a22 = this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)) == null ? void 0 : _a22.projects.forEach((canonicalPath) => {
508525
- ensureProjectsForOpenFiles = this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalPath, `Change in extended config file ${extendedConfigFileName} detected`) || ensureProjectsForOpenFiles;
508524
+ (_a22 = this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)) == null ? void 0 : _a22.projects.forEach((canonicalPath2) => {
508525
+ ensureProjectsForOpenFiles = this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalPath2, `Change in extended config file ${extendedConfigFileName} detected`) || ensureProjectsForOpenFiles;
508526
508526
  });
508527
508527
  if (ensureProjectsForOpenFiles) this.delayEnsureProjectForOpenFiles();
508528
508528
  },
@@ -567847,6 +567847,36 @@ function clip2(value2, max = 500) {
567847
567847
  function listLines(items, empty2 = "- none observed") {
567848
567848
  return items.length > 0 ? items.map((item) => `- ${item}`) : [empty2];
567849
567849
  }
567850
+ function formatWorkspaceInventorySummary(inventory) {
567851
+ if (!inventory)
567852
+ return ["- no bounded workspace inventory was provided"];
567853
+ const files = (inventory.files ?? []).slice(0, 40).map((file) => `${file.path}${file.bytes !== void 0 ? ` (bytes=${file.bytes}` : ""}${file.mtimeMs !== void 0 ? `${file.bytes !== void 0 ? ", " : " ("}mtimeMs=${file.mtimeMs})` : file.bytes !== void 0 ? ")" : ""}`);
567854
+ const dirs = (inventory.dirs ?? []).slice(0, 40).map((dir) => `dir:${dir}`);
567855
+ const summary = [
567856
+ `workspace_root=${inventory.root}`,
567857
+ `files=${inventory.files.length}${inventory.truncated ? "+" : ""}`,
567858
+ `dirs=${(inventory.dirs ?? []).length}`,
567859
+ `requested_max=${inventory.maxFiles}x${inventory.maxDirs}`
567860
+ ];
567861
+ if (!inventory.truncated)
567862
+ summary.push(`inventory_complete=${inventory.files.length > 0 || (inventory.dirs ?? []).length > 0 ? "yes" : "no"}`);
567863
+ const out = [
567864
+ `Generated at: ${inventory.generatedAtIso}`,
567865
+ summary.join("; ")
567866
+ ];
567867
+ if (files.length > 0) {
567868
+ out.push("Representative files:");
567869
+ out.push(...files.map((item) => `- ${item}`));
567870
+ }
567871
+ if (dirs.length > 0) {
567872
+ out.push("Representative directories:");
567873
+ out.push(...dirs.map((item) => `- ${item}`));
567874
+ }
567875
+ if (inventory.truncated) {
567876
+ out.push("- inventory_truncated: run a fresh scan with higher limits to inspect additional paths");
567877
+ }
567878
+ return out;
567879
+ }
567850
567880
  function formatEvidenceEntry(entry) {
567851
567881
  const parts = [
567852
567882
  entry.success === true ? "ok" : entry.success === false ? "failed" : "unknown",
@@ -567892,6 +567922,7 @@ ${String(input.answerText).trim()}` : ""
567892
567922
  ].filter(Boolean).join(" ");
567893
567923
  return `${clip2(file.path, 220)}${meta ? ` (${meta})` : ""}`;
567894
567924
  });
567925
+ const workspaceInventory = formatWorkspaceInventorySummary(input.workspaceInventory);
567895
567926
  const scenarioSeed = deriveScenarioSeed(input);
567896
567927
  const lines = [];
567897
567928
  lines.push(`[COMPLETION META-DECOMPOSITION]`);
@@ -567903,11 +567934,14 @@ ${String(input.answerText).trim()}` : ""
567903
567934
  lines.push(`Proposed completion claim text:`);
567904
567935
  lines.push(proposedClaimText || "(no proposed completion text yet)");
567905
567936
  lines.push(``);
567937
+ lines.push(`Open loops and remaining blockers:`);
567938
+ lines.push(...listLines(unresolvedSignals, "- no open loop / blocker signals currently reported"));
567939
+ lines.push(``);
567906
567940
  lines.push(`Observed run evidence:`);
567907
567941
  lines.push(...listLines(observedEvidence, "- no tool evidence recorded"));
567908
567942
  lines.push(``);
567909
- lines.push(`Unresolved or caution signals:`);
567910
- lines.push(...listLines(unresolvedSignals, "- none recorded"));
567943
+ lines.push(`Workspace inventory (bounded to prevent scan drift):`);
567944
+ lines.push(...workspaceInventory);
567911
567945
  lines.push(``);
567912
567946
  lines.push(`Modified artifact digest:`);
567913
567947
  lines.push(...listLines(modifiedFiles, "- no modified artifacts listed"));
@@ -567953,6 +567987,52 @@ var init_completionContract = __esm({
567953
567987
  // packages/orchestrator/dist/completionLedger.js
567954
567988
  import { mkdirSync as mkdirSync51, readFileSync as readFileSync66, writeFileSync as writeFileSync42 } from "node:fs";
567955
567989
  import { dirname as dirname29 } from "node:path";
567990
+ function setClaimDiscoveryState(ledger, state) {
567991
+ return {
567992
+ ...ledger,
567993
+ claimDiscovery: {
567994
+ ...state,
567995
+ generatedAtIso: nowIso3(),
567996
+ resolvedEvidenceHandles: state.resolvedEvidenceHandles ?? []
567997
+ },
567998
+ updatedAtIso: nowIso3()
567999
+ };
568000
+ }
568001
+ function claimDiscoveryStateFromSurvey(input) {
568002
+ const normalizedInventory = input.boundedInventory;
568003
+ const paths = [...new Set((Array.isArray(input.candidatePaths) ? input.candidatePaths : []).map((value2) => normalizeEvidencePath(value2)).filter(Boolean).slice(0, 16))];
568004
+ const reasons = /* @__PURE__ */ Object.create(null);
568005
+ for (const [rawPath, rawReason] of Object.entries(input.pathReasons ?? {})) {
568006
+ const path16 = normalizeEvidencePath(rawPath);
568007
+ const reason = cleanText(rawReason, 220);
568008
+ if (path16)
568009
+ reasons[path16] = reason || "candidate selected from bounded workspace inventory";
568010
+ }
568011
+ const openDeltas = paths.map((path16) => ({
568012
+ path: path16,
568013
+ reason: reasons[path16] || "candidate selected from bounded workspace inventory"
568014
+ }));
568015
+ const unresolved = Array.isArray(input.unresolvedQuestions) ? input.unresolvedQuestions.map((item) => cleanText(item, 260)).filter(Boolean) : [];
568016
+ const blockers = Array.isArray(input.survivingBlockers) ? input.survivingBlockers.map((item) => cleanText(item, 220)).filter(Boolean) : [];
568017
+ const hasBlockers = blockers.length > 0;
568018
+ const hasQuestions = unresolved.length > 0;
568019
+ const resolvedStatus = paths.length === 0 ? hasBlockers || hasQuestions ? "blocked" : "skipped" : hasBlockers || hasQuestions ? "blocked" : "active";
568020
+ return {
568021
+ status: resolvedStatus,
568022
+ generatedAtIso: nowIso3(),
568023
+ request: cleanText(input.request, 600),
568024
+ context: cleanText(input.context, 480),
568025
+ boundedInventory: normalizedInventory,
568026
+ candidatePaths: paths,
568027
+ pathReasons: reasons,
568028
+ unresolvedQuestions: unresolved.slice(0, 10),
568029
+ openDeltas,
568030
+ survivingBlockers: blockers.slice(0, 8),
568031
+ evidenceHandles: [...new Set(paths.map((path16) => `workspace:${path16}`))],
568032
+ resolvedEvidenceHandles: [],
568033
+ requiresEvidence: typeof input.requiresEvidence === "boolean" ? input.requiresEvidence : true
568034
+ };
568035
+ }
567956
568036
  function nowIso3(now2 = /* @__PURE__ */ new Date()) {
567957
568037
  return now2 instanceof Date ? now2.toISOString() : new Date(now2).toISOString();
567958
568038
  }
@@ -568002,6 +568082,180 @@ function formatEvidenceSummary(summary) {
568002
568082
  function nextId2(prefix, count) {
568003
568083
  return `${prefix}_${String(count + 1).padStart(4, "0")}`;
568004
568084
  }
568085
+ function extractWorkspaceTokens(text2) {
568086
+ const raw = String(text2 ?? "").toLowerCase().replace(/["'`]/g, " ").replace(/[^\w./@-]+/g, " ");
568087
+ return raw.split(/\s+/).filter((value2) => value2.length >= 4);
568088
+ }
568089
+ function extractPathFragments(text2) {
568090
+ const out = [];
568091
+ const pathPattern = /(?:[\w.-]+\/[\w./-]+\.[A-Za-z0-9]+|[\w.-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|cpp|c|h|hpp|java|kt|json|yml|yaml|toml|md|mdx|sh|bash|cxx|swift|rb|php)|[\w./-]+\.[A-Za-z0-9]+)/g;
568092
+ for (const hit of text2.matchAll(pathPattern)) {
568093
+ const value2 = String(hit[0] ?? "").trim();
568094
+ if (!value2)
568095
+ continue;
568096
+ const normalized = value2.replace(/^\.\/+/, "");
568097
+ if (normalized.length > 2)
568098
+ out.push(normalized);
568099
+ }
568100
+ return [...new Set(out)].slice(0, 12);
568101
+ }
568102
+ function tokenizeClaims(text2) {
568103
+ return String(text2 ?? "").split(/[.\n\r!?;]+/).map((item) => item.trim()).filter((item) => item.length > 6).filter((item) => item.length < 260).slice(0, 30);
568104
+ }
568105
+ function estimateClaimMateriality(text2) {
568106
+ const normalized = text2.toLowerCase();
568107
+ if (/\b(blocker|critical|security|production|release|deploy|migrate|migration|regression|customer|public)\b/.test(normalized)) {
568108
+ return "high";
568109
+ }
568110
+ if (/\b(implement|fix|refactor|resolve|wire|integrat|add|remove|change|update)\b/.test(normalized)) {
568111
+ return "medium";
568112
+ }
568113
+ return "low";
568114
+ }
568115
+ function classifyClaimAttainedState(text2) {
568116
+ const normalized = text2.toLowerCase();
568117
+ if (/\b(block|blocked|blocker|cannot verify|unverified|not verified|hold)\b/.test(normalized)) {
568118
+ return "blocked";
568119
+ }
568120
+ if (/\b(simulat|dry.?run|mock|unit test|paper|offline|software.?in.?loop)\b/.test(normalized)) {
568121
+ return "simulation_only";
568122
+ }
568123
+ if (/\b(hil|hardware.?in.?the.?loop|hardware.?test|on.?device|real.?hardware|physical)\b/.test(normalized)) {
568124
+ return "hardware_verified";
568125
+ }
568126
+ if (/\b(integrat|integrated|bridge|transport|serial|can|hardware|device|physical)\b/.test(normalized)) {
568127
+ return "hardware_integrated";
568128
+ }
568129
+ return "unproven";
568130
+ }
568131
+ function deriveClaimRisks(text2) {
568132
+ const normalized = text2.toLowerCase();
568133
+ if (/\b(start|running|daemon|process|service|alive|ready)\b/.test(normalized)) {
568134
+ return {
568135
+ riskCategory: "process_liveness",
568136
+ requiresIndependentEvidence: true,
568137
+ requiredCheck: "Independent runtime state/health check with process or endpoint probe."
568138
+ };
568139
+ }
568140
+ if (/\b(instal|pip|npm|pnpm|apt|brew|cargo|go install|pip install|docker pull)\b/.test(normalized)) {
568141
+ return {
568142
+ riskCategory: "installation",
568143
+ requiresIndependentEvidence: true,
568144
+ requiredCheck: "Independent command query/inspection proving the toolchain exists after the installation claim."
568145
+ };
568146
+ }
568147
+ if (/\b(fixed|repair|resolved|passed|test pass|fix|bug|regression)\b/.test(normalized)) {
568148
+ return {
568149
+ riskCategory: "fix_confirmation",
568150
+ requiresIndependentEvidence: true,
568151
+ requiredCheck: "Re-run the same failure path or equivalent check and capture the successful evidence."
568152
+ };
568153
+ }
568154
+ if (/\b(simulat|dry.?run|mock|fake|virtual)\b/.test(normalized)) {
568155
+ return {
568156
+ riskCategory: "reality",
568157
+ requiresIndependentEvidence: false,
568158
+ requiredCheck: "Label and preserve as simulation-only unless hardware-path evidence exists."
568159
+ };
568160
+ }
568161
+ return {
568162
+ riskCategory: "coverage",
568163
+ requiresIndependentEvidence: false,
568164
+ requiredCheck: "Collect evidence per claim from supported tool outputs and source observations."
568165
+ };
568166
+ }
568167
+ function claimEvidenceNeeds(text2) {
568168
+ const normalized = text2.toLowerCase();
568169
+ const needs = [];
568170
+ const kind = /\b(test|verify|validate|coverage|run|build|lint|check|execute)\b/.test(normalized) ? "tool_result" : /\b(create|write|modify|edit|delete|remove|add|updated|implemented|fix)\b/.test(normalized) ? "file_change" : "runtime_observation";
568171
+ needs.push({
568172
+ handle: `${kind}:in_scope`,
568173
+ evidenceKind: kind,
568174
+ rationale: `Evidence supporting the in-scope portion of: ${cleanText(text2, 120)}`
568175
+ });
568176
+ if (/\b(runtime|process|service|daemon|endpoint|server)\b/.test(normalized)) {
568177
+ needs.push({
568178
+ handle: "verification:post-change",
568179
+ evidenceKind: "runtime_observation",
568180
+ rationale: "Observed runtime confirmation after the claimed change."
568181
+ });
568182
+ }
568183
+ if (/\b(serial|hardware|device|controller|transport)\b/.test(normalized)) {
568184
+ needs.push({
568185
+ handle: "delivery:hardware-path",
568186
+ evidenceKind: "delivery",
568187
+ rationale: "Hardware-path or transport evidence that clarifies simulation/hardware status."
568188
+ });
568189
+ }
568190
+ return needs;
568191
+ }
568192
+ function findInventoryMatches(statement, workspaceInventory) {
568193
+ if (!workspaceInventory)
568194
+ return [];
568195
+ const tokens = extractWorkspaceTokens(statement);
568196
+ const candidatePaths = workspaceInventory.files.map((entry) => entry.path);
568197
+ const seen = /* @__PURE__ */ new Set();
568198
+ const matches = [];
568199
+ const literalPathHints = extractPathFragments(statement);
568200
+ for (const hint of literalPathHints) {
568201
+ const normalized = hint.toLowerCase();
568202
+ const exact = candidatePaths.find((path16) => path16.toLowerCase() === normalized);
568203
+ if (exact)
568204
+ seen.add(exact);
568205
+ }
568206
+ for (const path16 of candidatePaths) {
568207
+ if (matches.length >= 5 || seen.size >= 8)
568208
+ break;
568209
+ const lower = path16.toLowerCase();
568210
+ const tokenHits = tokens.filter((token) => lower.includes(token));
568211
+ if (tokenHits.length >= 2 || tokenHits.length >= 1 && literalPathHints.length === 0) {
568212
+ if (!seen.has(path16)) {
568213
+ seen.add(path16);
568214
+ }
568215
+ }
568216
+ }
568217
+ for (const path16 of seen)
568218
+ matches.push(path16);
568219
+ if (literalPathHints.length > 0 && matches.length === 0) {
568220
+ for (const path16 of candidatePaths) {
568221
+ for (const hint of literalPathHints) {
568222
+ if (path16.toLowerCase().includes(hint.toLowerCase())) {
568223
+ matches.push(path16);
568224
+ break;
568225
+ }
568226
+ }
568227
+ if (matches.length >= 6)
568228
+ break;
568229
+ }
568230
+ }
568231
+ return matches.slice(0, 6);
568232
+ }
568233
+ function claimDiscoveryControllerSignals(stage2) {
568234
+ if (!stage2)
568235
+ return [];
568236
+ const openDeltas = (stage2.openDeltas ?? []).slice(0, 10);
568237
+ const evidenceHandles = stage2.evidenceHandles ?? [];
568238
+ const resolvedEvidenceHandles = stage2.resolvedEvidenceHandles ?? [];
568239
+ const survivingBlockers = stage2.survivingBlockers ?? [];
568240
+ const unresolvedQuestions = stage2.unresolvedQuestions ?? [];
568241
+ const boundedInventory = stage2.boundedInventory;
568242
+ const boundedDirs = boundedInventory?.dirs ?? [];
568243
+ const resolvedCount = Math.min(evidenceHandles.length, new Set(resolvedEvidenceHandles).size);
568244
+ const unresolvedEvidenceCount = Math.max(evidenceHandles.length - resolvedCount, 0);
568245
+ return [
568246
+ "[COMPLETION CLAIM DISCOVERY]",
568247
+ `status=${stage2.status ?? "skipped"} generated_at=${stage2.generatedAtIso ?? ""}`,
568248
+ `requires_evidence=${stage2.requiresEvidence ? "true" : "false"}`,
568249
+ `bounded_inventory=${boundedInventory ? `${boundedInventory.root}|files=${boundedInventory.files.length}|dirs=${boundedDirs.length}|truncated=${Boolean(boundedInventory.truncated)}` : "none"}`,
568250
+ `candidate_paths=${(stage2.candidatePaths ?? []).join(",") || "none"}`,
568251
+ `open_deltas=${openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`.replace(/\s+/g, " ")).join(" | ") || "none"}`,
568252
+ `open_delta_count=${openDeltas.length} unresolved_evidence_count=${unresolvedEvidenceCount}`,
568253
+ `surviving_blockers=${survivingBlockers.join(" | ") || "none"}`,
568254
+ `unresolved_questions=${unresolvedQuestions.join(" | ") || "none"}`,
568255
+ `evidence_handles=${evidenceHandles.join(",") || "none"}`,
568256
+ `resolved_evidence_handles=${resolvedEvidenceHandles.join(",") || "none"}`
568257
+ ];
568258
+ }
568005
568259
  function createCompletionLedger(input) {
568006
568260
  const ts = nowIso3(input.now);
568007
568261
  return {
@@ -568018,28 +568272,68 @@ function createCompletionLedger(input) {
568018
568272
  };
568019
568273
  }
568020
568274
  function deriveClaimsFromProposedText(input) {
568021
- const raw = String(input.text ?? "").trim();
568022
- if (!raw)
568275
+ return deriveStructuredClaims({
568276
+ taskText: input.taskText,
568277
+ proposedSummary: input.text,
568278
+ source: input.source,
568279
+ existing: input.existing,
568280
+ workspaceInventory: input.workspaceInventory,
568281
+ maxClaims: 12
568282
+ });
568283
+ }
568284
+ function deriveStructuredClaims(input) {
568285
+ const proposed = String(input.proposedSummary ?? "").trim();
568286
+ const task = String(input.taskText ?? "").trim();
568287
+ const baseText = [proposed, task].filter(Boolean).join("\n");
568288
+ const statements = tokenizeClaims(baseText);
568289
+ if (statements.length === 0)
568023
568290
  return [];
568024
568291
  const existingIds = new Set((input.existing ?? []).map((claim) => claim.id));
568025
- const text2 = cleanText(raw, 1200);
568026
- const base3 = normalizeCompletionKey(text2, "claim").slice(0, 64);
568027
- let id2 = base3 || "claim";
568028
- let suffix = 2;
568029
- while (existingIds.has(id2)) {
568030
- id2 = `${base3}_${suffix++}`;
568031
- }
568032
- return [
568033
- {
568292
+ const maxClaims = Math.max(1, Math.min(32, input.maxClaims ?? 12));
568293
+ const seen = /* @__PURE__ */ new Set();
568294
+ const claims = [];
568295
+ for (const statementRaw of statements) {
568296
+ if (claims.length >= maxClaims)
568297
+ break;
568298
+ const text2 = cleanText(statementRaw, 220);
568299
+ if (!text2)
568300
+ continue;
568301
+ const base3 = normalizeCompletionKey(text2, "claim").slice(0, 64) || "claim";
568302
+ let id2 = base3;
568303
+ let suffix = 2;
568304
+ while (existingIds.has(id2) || seen.has(id2)) {
568305
+ id2 = `${base3}_${suffix++}`;
568306
+ }
568307
+ const risk = deriveClaimRisks(text2);
568308
+ const needs = claimEvidenceNeeds(text2);
568309
+ const evidenceHandles = [
568310
+ ...needs.map((need) => need.handle),
568311
+ ...findInventoryMatches(text2, input.workspaceInventory).map((path16) => `workspace:${path16}`)
568312
+ ];
568313
+ const workspaceSignals = findInventoryMatches(text2, input.workspaceInventory);
568314
+ const sourceSignals = [
568315
+ input.taskText ? "task" : "proposed_text",
568316
+ ...extractPathFragments(statementRaw).slice(0, 2)
568317
+ ].filter(Boolean);
568318
+ claims.push({
568034
568319
  id: id2,
568035
568320
  text: text2,
568036
- source: input.source,
568037
- materiality: "high",
568038
- evidenceRequirement: "Explicit evidenceIds must be attached by the caller, or the claim remains unverified for critic review.",
568321
+ source: input.source ?? "derived",
568322
+ materiality: estimateClaimMateriality(statementRaw),
568323
+ evidenceRequirement: "Attach explicit evidenceIds that match the listed evidence handles and state.",
568324
+ attainedState: classifyClaimAttainedState(text2),
568325
+ riskCategory: risk.riskCategory,
568326
+ requiresIndependentEvidence: risk.requiresIndependentEvidence,
568327
+ requiredCheck: risk.requiredCheck,
568328
+ evidenceNeeds: needs,
568329
+ sourceSignals,
568330
+ workspaceSignals,
568039
568331
  evidenceIds: [],
568040
568332
  status: "unverified"
568041
- }
568042
- ];
568333
+ });
568334
+ seen.add(id2);
568335
+ }
568336
+ return claims;
568043
568337
  }
568044
568338
  function recordCompletionEvidence(ledger, evidence) {
568045
568339
  const targetPaths = cleanTargetPaths(evidence.targetPaths);
@@ -568138,14 +568432,42 @@ function buildCriticPacketFromLedger(ledger) {
568138
568432
  lines.push(`Run: ${ledger.runId}`);
568139
568433
  lines.push(`Goal: ${ledger.goal || "(not recorded)"}`);
568140
568434
  lines.push(`Status: ${ledger.status}`);
568435
+ lines.push(`Claims discovered: ${ledger.proposedClaims.length}`);
568436
+ if (ledger.claimDiscovery) {
568437
+ lines.push("");
568438
+ lines.push("Claim Discovery:");
568439
+ lines.push(` status=${ledger.claimDiscovery.status}`);
568440
+ lines.push(` generated_at=${ledger.claimDiscovery.generatedAtIso}`);
568441
+ lines.push(` candidate_paths=${ledger.claimDiscovery.candidatePaths.join(",") || "none"}`);
568442
+ lines.push(` open_deltas=${ledger.claimDiscovery.openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`).slice(0, 10).join(" | ") || "none"}`);
568443
+ lines.push(` surviving_blockers=${ledger.claimDiscovery.survivingBlockers.join(" | ") || "none"}`);
568444
+ lines.push(` unresolved_questions=${ledger.claimDiscovery.unresolvedQuestions.join(" | ") || "none"}`);
568445
+ lines.push(` evidence_handles=${ledger.claimDiscovery.evidenceHandles.join(",") || "none"}`);
568446
+ lines.push(` resolved_evidence_handles=${ledger.claimDiscovery.resolvedEvidenceHandles.join(",") || "none"}`);
568447
+ }
568141
568448
  lines.push("");
568142
568449
  lines.push("Claims:");
568143
568450
  if (ledger.proposedClaims.length === 0)
568144
568451
  lines.push("- none recorded");
568145
568452
  for (const claim of ledger.proposedClaims) {
568146
- lines.push(`- [${claim.status}] ${claim.id}: ${claim.text}`);
568453
+ const handles = claim.evidenceNeeds.length === 0 ? "none" : claim.evidenceNeeds.map((need) => need.handle).join(", ");
568454
+ lines.push(`- [${claim.status}] ${claim.id} (${claim.attainedState}): ${claim.text}`);
568455
+ lines.push(` source: ${claim.source} materiality:${claim.materiality}`);
568147
568456
  lines.push(` evidence: ${claim.evidenceIds.length > 0 ? claim.evidenceIds.join(", ") : "none"}`);
568148
- lines.push(` requirement: ${claim.evidenceRequirement}`);
568457
+ lines.push(` evidence_handles: ${handles}`);
568458
+ if (claim.workspaceSignals.length > 0) {
568459
+ lines.push(` workspace_signals: ${claim.workspaceSignals.join(", ")}`);
568460
+ }
568461
+ if (claim.sourceSignals.length > 0) {
568462
+ lines.push(` source_signals: ${claim.sourceSignals.join(", ")}`);
568463
+ }
568464
+ lines.push(` requirement: ${claim.evidenceRequirement} ${claim.requiresIndependentEvidence ? "[independent evidence required]" : ""}`);
568465
+ if (claim.riskCategory && claim.riskCategory !== "unknown") {
568466
+ lines.push(` risk: ${claim.riskCategory}`);
568467
+ if (claim.requiredCheck) {
568468
+ lines.push(` required_check: ${claim.requiredCheck}`);
568469
+ }
568470
+ }
568149
568471
  }
568150
568472
  lines.push("");
568151
568473
  lines.push("Evidence:");
@@ -568232,6 +568554,27 @@ function evidenceTargetPaths(entry) {
568232
568554
  }
568233
568555
  return cleanTargetPaths(paths);
568234
568556
  }
568557
+ function claimDiscoveryResolvedHandles(ledger, state) {
568558
+ if (!state)
568559
+ return [];
568560
+ const inspected = /* @__PURE__ */ new Set();
568561
+ const candidatePaths = [...state.candidatePaths].map((value2) => normalizeEvidencePath(value2)).filter(Boolean).map((path16) => path16.replace(/^\/+/, ""));
568562
+ for (const entry of ledger.evidence) {
568563
+ if (entry.success !== true)
568564
+ continue;
568565
+ for (const rawPath of evidenceTargetPaths(entry)) {
568566
+ const path16 = normalizeEvidencePath(rawPath);
568567
+ if (!path16)
568568
+ continue;
568569
+ const normalized = path16.replace(/^\/+/, "");
568570
+ const matched = candidatePaths.find((candidate) => pathsEquivalent(candidate, normalized));
568571
+ if (matched) {
568572
+ inspected.add(`workspace:${matched}`);
568573
+ }
568574
+ }
568575
+ }
568576
+ return [...inspected];
568577
+ }
568235
568578
  function pathsEquivalent(a2, b) {
568236
568579
  const left = normalizeEvidencePath(a2);
568237
568580
  const right = normalizeEvidencePath(b);
@@ -568803,18 +569146,41 @@ function clean3(value2, max) {
568803
569146
  return String(value2 ?? "").replace(/\s+/g, " ").trim().slice(0, max);
568804
569147
  }
568805
569148
  function selectedEvidence(ledger) {
568806
- if (!ledger)
568807
- return { evidenceIds: [], artifactHashes: [] };
569149
+ if (!ledger) {
569150
+ return {
569151
+ evidenceIds: [],
569152
+ commandReceipts: [],
569153
+ artifactHashes: []
569154
+ };
569155
+ }
568808
569156
  const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation")).slice(-16);
568809
569157
  const artifacts = /* @__PURE__ */ new Map();
569158
+ const commandReceipts = [];
568810
569159
  for (const entry of candidates) {
568811
569160
  for (const item of entry.receipt?.artifactHashes ?? []) {
568812
569161
  if (item.path && item.sha256)
568813
569162
  artifacts.set(item.path, item.sha256);
568814
569163
  }
569164
+ if (entry.receipt) {
569165
+ const receipt = entry.receipt;
569166
+ commandReceipts.push({
569167
+ evidenceId: entry.id,
569168
+ toolName: entry.toolName ?? "unknown",
569169
+ role: entry.role ?? "unknown",
569170
+ command: receipt.command ?? "",
569171
+ canonicalCommand: receipt.canonicalCommand ?? "",
569172
+ cwd: receipt.cwd ?? "",
569173
+ exitCode: receipt.exitCode ?? null,
569174
+ timedOut: Boolean(receipt.timedOut),
569175
+ startedAtIso: receipt.startedAtIso ?? "",
569176
+ finishedAtIso: receipt.finishedAtIso ?? "",
569177
+ artifactHashes: entry.receipt.artifactHashes?.length ? entry.receipt.artifactHashes : []
569178
+ });
569179
+ }
568815
569180
  }
568816
569181
  return {
568817
569182
  evidenceIds: candidates.map((entry) => entry.id),
569183
+ commandReceipts,
568818
569184
  artifactHashes: [...artifacts.entries()].map(([path16, sha2567]) => ({
568819
569185
  path: path16,
568820
569186
  sha256: sha2567
@@ -568842,6 +569208,7 @@ function buildCompletionFinalizationRecord(input) {
568842
569208
  summary: clean3(input.summary, 4e3),
568843
569209
  committedAtIso,
568844
569210
  evidenceIds: evidence.evidenceIds,
569211
+ commandReceipts: evidence.commandReceipts,
568845
569212
  artifactHashes: evidence.artifactHashes,
568846
569213
  projections: {
568847
569214
  ledger: "pending",
@@ -571564,6 +571931,13 @@ function buildReferenceContractBundle(input) {
571564
571931
  });
571565
571932
  }
571566
571933
  }
571934
+ if (input.includeDeliverySurface && !candidates.some((candidate) => candidate.id === "delivery_surface")) {
571935
+ candidates.push({
571936
+ id: "delivery_surface",
571937
+ phase: input.phase,
571938
+ reason: "workspace_delivery_coverage_manifest"
571939
+ });
571940
+ }
571567
571941
  if (input.includeExplicit !== false) {
571568
571942
  for (const id2 of explicitContractIds(input.explicitModules)) {
571569
571943
  candidates.push({
@@ -571711,10 +572085,10 @@ var init_phase_skill_guidance = __esm({
571711
572085
  "use strict";
571712
572086
  init_dist5();
571713
572087
  PHASE_FOCUS = {
571714
- explore: "repository discovery requirements analysis source inspection provenance",
571715
- plan: "requirements planning architecture design acceptance criteria risk analysis",
572088
+ explore: "repository discovery requirements analysis source inspection provenance capability boundary falsification",
572089
+ plan: "requirements planning architecture design acceptance criteria claim evidence risk analysis",
571716
572090
  implement: "implementation code change editing debugging tests integration safety",
571717
- verify: "verification validation acceptance tests release documentation consistency",
572091
+ verify: "verification validation acceptance tests evidence receipts release documentation consistency",
571718
572092
  mixed: "implementation verification testing code review evidence"
571719
572093
  };
571720
572094
  }
@@ -571725,6 +572099,9 @@ import { createHash as createHash30 } from "node:crypto";
571725
572099
  import { existsSync as existsSync90, readFileSync as readFileSync70 } from "node:fs";
571726
572100
  import { join as join102 } from "node:path";
571727
572101
  import { z as z17 } from "zod";
572102
+ function canonicalPath(path16) {
572103
+ return String(path16 ?? "").trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
572104
+ }
571728
572105
  function duplicates(values) {
571729
572106
  const seen = /* @__PURE__ */ new Set();
571730
572107
  const out = /* @__PURE__ */ new Set();
@@ -571770,17 +572147,25 @@ function normalizeEvidence2(availableEvidence) {
571770
572147
  }
571771
572148
  return evidence;
571772
572149
  }
571773
- function evaluateDeliveryCoverage(manifest, availableEvidenceIds = []) {
572150
+ function evaluateDeliveryCoverage(manifest, availableEvidenceIds = [], sourceObservations = []) {
571774
572151
  const gaps = [];
571775
572152
  const sourceById = new Map(manifest.sources.map((item) => [item.id, item]));
571776
572153
  const contractById = new Map(manifest.contracts.map((item) => [item.id, item]));
571777
572154
  const acceptanceById = new Map(manifest.acceptance.map((item) => [item.id, item]));
572155
+ const inspectionById = new Map(manifest.inspections.map((item) => [item.id, item]));
572156
+ const contradictionById = new Map(manifest.contradictionChecks.map((item) => [item.id, item]));
571778
572157
  const availableEvidence = normalizeEvidence2(availableEvidenceIds);
571779
572158
  const available = new Set(availableEvidence.map((item) => item.id));
572159
+ const observations = [...sourceObservations].map((item) => ({
572160
+ ...item,
572161
+ path: canonicalPath(item.path)
572162
+ }));
571780
572163
  for (const id2 of duplicates([
571781
572164
  ...manifest.sources.map((item) => item.id),
571782
572165
  ...manifest.contracts.map((item) => item.id),
571783
572166
  ...manifest.acceptance.map((item) => item.id),
572167
+ ...manifest.inspections.map((item) => item.id),
572168
+ ...manifest.contradictionChecks.map((item) => item.id),
571784
572169
  ...manifest.claims.map((item) => item.id)
571785
572170
  ])) {
571786
572171
  gaps.push({ claimId: id2, code: "duplicate_id", detail: `Duplicate manifest id '${id2}'.` });
@@ -571801,6 +572186,7 @@ function evaluateDeliveryCoverage(manifest, availableEvidenceIds = []) {
571801
572186
  }
571802
572187
  }
571803
572188
  const claimStates = manifest.claims.map((claim) => {
572189
+ const gapsBeforeClaim = gaps.length;
571804
572190
  for (const sourceId of claim.sourceIds) {
571805
572191
  if (!sourceById.has(sourceId)) {
571806
572192
  gaps.push({ claimId: claim.id, code: "unknown_source", detail: `Claim references unknown source '${sourceId}'.` });
@@ -571854,6 +572240,57 @@ function evaluateDeliveryCoverage(manifest, availableEvidenceIds = []) {
571854
572240
  if (claim.state === "blocked" && !claim.blockedReason) {
571855
572241
  gaps.push({ claimId: claim.id, code: "blocked_reason_required", detail: "Blocked claims require a concrete blockedReason." });
571856
572242
  }
572243
+ if (manifest.schemaVersion >= 2 && claim.state !== "blocked" && (claim.requiredInspectionIds.length === 0 || claim.requiredContradictionCheckIds.length === 0)) {
572244
+ gaps.push({
572245
+ claimId: claim.id,
572246
+ code: "missing_inspection_contract",
572247
+ detail: "V2 non-blocked claims must name source inspections and contradiction checks."
572248
+ });
572249
+ }
572250
+ const missingInspectionIds = [];
572251
+ for (const inspectionId of claim.requiredInspectionIds) {
572252
+ const inspection = inspectionById.get(inspectionId);
572253
+ if (!inspection) {
572254
+ missingInspectionIds.push(inspectionId);
572255
+ gaps.push({ claimId: claim.id, code: "unknown_inspection", detail: `Claim references unknown inspection '${inspectionId}'.` });
572256
+ continue;
572257
+ }
572258
+ const unsatisfiedPaths = inspection.targetPaths.filter((path16) => {
572259
+ const normalizedPath = canonicalPath(path16);
572260
+ return !observations.some((observation) => observation.path === normalizedPath && observation.stale !== true && observation.fidelity === "full" && Boolean(observation.contentHash));
572261
+ });
572262
+ if (unsatisfiedPaths.length > 0) {
572263
+ missingInspectionIds.push(inspectionId);
572264
+ const observedButUnusable = unsatisfiedPaths.some((path16) => observations.some((observation) => observation.path === canonicalPath(path16)));
572265
+ gaps.push({
572266
+ claimId: claim.id,
572267
+ code: observedButUnusable ? "stale_inspection" : "missing_inspection",
572268
+ detail: `${inspection.boundary} inspection '${inspectionId}' needs fresh full hashed read(s): ${unsatisfiedPaths.join(", ")}.`
572269
+ });
572270
+ }
572271
+ }
572272
+ const missingContradictionCheckIds = [];
572273
+ for (const checkId of claim.requiredContradictionCheckIds) {
572274
+ const check = contradictionById.get(checkId);
572275
+ if (!check) {
572276
+ missingContradictionCheckIds.push(checkId);
572277
+ gaps.push({ claimId: claim.id, code: "unknown_contradiction_check", detail: `Claim references unknown contradiction check '${checkId}'.` });
572278
+ continue;
572279
+ }
572280
+ const unresolvedInspectionIds = check.inspectionIds.filter((id2) => {
572281
+ if (!claim.requiredInspectionIds.includes(id2))
572282
+ return true;
572283
+ return missingInspectionIds.includes(id2);
572284
+ });
572285
+ if (unresolvedInspectionIds.length > 0) {
572286
+ missingContradictionCheckIds.push(checkId);
572287
+ gaps.push({
572288
+ claimId: claim.id,
572289
+ code: "missing_contradiction_check",
572290
+ detail: `Contradiction check '${checkId}' (${check.question}) lacks fresh inspection evidence: ${unresolvedInspectionIds.join(", ")}.`
572291
+ });
572292
+ }
572293
+ }
571857
572294
  const required = requiredLayers(claim.state);
571858
572295
  const selected = claim.requiredAcceptanceIds.map((id2) => acceptanceById.get(id2)).filter((item) => Boolean(item));
571859
572296
  const missingAcceptanceIds = required.filter((layer) => !selected.some((item) => item.layer === layer && item.requiredFor.includes(claim.state)));
@@ -571884,11 +572321,16 @@ function evaluateDeliveryCoverage(manifest, availableEvidenceIds = []) {
571884
572321
  gaps.push({ claimId: claim.id, code: "missing_evidence", detail: `Evidence receipt(s) are not present in this run: ${missingEvidence.join(", ")}.` });
571885
572322
  }
571886
572323
  }
572324
+ const claimHasGap = gaps.slice(gapsBeforeClaim).some((gap) => gap.claimId === claim.id);
572325
+ const attainedState = claim.state === "blocked" ? "blocked" : claimHasGap ? "unproven" : claim.state;
571887
572326
  return {
571888
572327
  id: claim.id,
571889
572328
  state: claim.state,
572329
+ attainedState,
571890
572330
  evidenceIds: claim.evidenceIds,
571891
- missingAcceptanceIds
572331
+ missingAcceptanceIds,
572332
+ missingInspectionIds,
572333
+ missingContradictionCheckIds
571892
572334
  };
571893
572335
  });
571894
572336
  return {
@@ -571916,7 +572358,7 @@ function renderDeliveryCoverageState(evaluation, sourcePath) {
571916
572358
  `sha256=${evaluation.manifestHash}`,
571917
572359
  `completion_ready=${evaluation.completionReady}`,
571918
572360
  "claims:",
571919
- ...evaluation.claimStates.slice(0, 12).map((claim) => `- id=${claim.id} state=${claim.state} evidence=${claim.evidenceIds.join(",") || "none"} missing_acceptance=${claim.missingAcceptanceIds.join(",") || "none"}`),
572361
+ ...evaluation.claimStates.slice(0, 12).map((claim) => `- id=${claim.id} state=${claim.state} attained=${claim.attainedState} evidence=${claim.evidenceIds.join(",") || "none"} missing_inspection=${claim.missingInspectionIds.join(",") || "none"} missing_contradiction=${claim.missingContradictionCheckIds.join(",") || "none"} missing_acceptance=${claim.missingAcceptanceIds.join(",") || "none"}`),
571920
572362
  "gaps:",
571921
572363
  ...evaluation.gaps.length > 0 ? evaluation.gaps.slice(0, 12).map((gap) => `- [${gap.code}] ${gap.claimId}: ${gap.detail}`) : ["- none"],
571922
572364
  "Treat this as delivery truth, not a recovery directive. A blocked or simulation-only claim must remain labeled at that state.",
@@ -571924,7 +572366,7 @@ function renderDeliveryCoverageState(evaluation, sourcePath) {
571924
572366
  ];
571925
572367
  return lines.join("\n");
571926
572368
  }
571927
- var deliveryRealityStates, acceptanceLayers, sourceSchema, contractSchema, acceptanceSchema, subjectSchema, claimSchema, deliveryCoverageManifestSchema;
572369
+ var deliveryRealityStates, acceptanceLayers, sourceSchema, contractSchema, acceptanceSchema, inspectionSchema, contradictionCheckSchema, subjectSchema, claimSchema, deliveryCoverageManifestSchema;
571928
572370
  var init_deliveryCoverage = __esm({
571929
572371
  "packages/orchestrator/dist/deliveryCoverage.js"() {
571930
572372
  "use strict";
@@ -571966,6 +572408,17 @@ var init_deliveryCoverage = __esm({
571966
572408
  verificationCommands: z17.array(z17.string().min(1)).min(1),
571967
572409
  safetyInterlock: z17.string().min(1).optional()
571968
572410
  });
572411
+ inspectionSchema = z17.object({
572412
+ id: z17.string().min(1),
572413
+ boundary: z17.string().min(1),
572414
+ targetPaths: z17.array(z17.string().min(1)).min(1),
572415
+ proves: z17.string().min(1)
572416
+ });
572417
+ contradictionCheckSchema = z17.object({
572418
+ id: z17.string().min(1),
572419
+ question: z17.string().min(1),
572420
+ inspectionIds: z17.array(z17.string().min(1)).min(1)
572421
+ });
571969
572422
  subjectSchema = z17.object({
571970
572423
  productSeries: z17.string().min(1),
571971
572424
  commands: z17.array(z17.string().min(1)).default([]),
@@ -571980,13 +572433,21 @@ var init_deliveryCoverage = __esm({
571980
572433
  sourceIds: z17.array(z17.string().min(1)).min(1),
571981
572434
  evidenceIds: z17.array(z17.string().min(1)).default([]),
571982
572435
  requiredAcceptanceIds: z17.array(z17.string().min(1)).default([]),
572436
+ /** Source boundaries that must be freshly read before this claim is true. */
572437
+ requiredInspectionIds: z17.array(z17.string().min(1)).default([]),
572438
+ /** Falsification checks that must be grounded in those source inspections. */
572439
+ requiredContradictionCheckIds: z17.array(z17.string().min(1)).default([]),
571983
572440
  blockedReason: z17.string().min(1).optional()
571984
572441
  });
571985
572442
  deliveryCoverageManifestSchema = z17.object({
571986
- schemaVersion: z17.literal(1),
572443
+ // Version 1 remains readable for existing workspaces. Version 2 activates
572444
+ // claim-driven source inspection and falsification gates.
572445
+ schemaVersion: z17.union([z17.literal(1), z17.literal(2)]),
571987
572446
  sources: z17.array(sourceSchema),
571988
572447
  contracts: z17.array(contractSchema),
571989
572448
  acceptance: z17.array(acceptanceSchema),
572449
+ inspections: z17.array(inspectionSchema).default([]),
572450
+ contradictionChecks: z17.array(contradictionCheckSchema).default([]),
571990
572451
  claims: z17.array(claimSchema)
571991
572452
  });
571992
572453
  }
@@ -577801,16 +578262,90 @@ var init_consolidation_runtime = __esm({
577801
578262
  });
577802
578263
 
577803
578264
  // packages/orchestrator/dist/completion-evidence-gate.js
578265
+ function normalizedEvidenceText(text2) {
578266
+ return String(text2 ?? "").toLowerCase();
578267
+ }
577804
578268
  function classifyCompletionClaim(text2) {
577805
- void text2;
578269
+ const normalized = normalizedEvidenceText(text2);
578270
+ if (!normalized) {
578271
+ return {
578272
+ category: null,
578273
+ requiresIndependentEvidence: false,
578274
+ requiredCheck: ""
578275
+ };
578276
+ }
578277
+ const processLiveness = /\b(daemon|service|process|server|port|listener|runtime|pid|socket|endpoint)\b/.test(normalized) && /\b(start(ed|ing)?|run(ning)?|up|ready|alive|online|boot(ed|ing)?|initialized|listening)\b/.test(normalized);
578278
+ if (processLiveness) {
578279
+ return {
578280
+ category: "process_liveness",
578281
+ requiresIndependentEvidence: true,
578282
+ requiredCheck: "Independent runtime verification (process/pid/health/port check) after the claimed state change."
578283
+ };
578284
+ }
578285
+ if (/\b(instal|npm|pnpm|yarn|pip\s+install|go\s+install|cargo\s+install|apt\s+get|brew\s+install|dnf|yum|apk add|make\s+install)\b/.test(normalized)) {
578286
+ return {
578287
+ category: "installation",
578288
+ requiresIndependentEvidence: true,
578289
+ requiredCheck: "Independent command-level availability check for the installed artifact after change."
578290
+ };
578291
+ }
578292
+ const fixHint = /(fix|fixed|resolved|repair|patched|correct|address|addressed)\b/.test(normalized);
578293
+ const fixTarget = /(bug|regression|failure|error|issue|test|build|lint|crash|exception|pass|coverage)\b/.test(normalized);
578294
+ if (fixHint && fixTarget) {
578295
+ return {
578296
+ category: "fix_confirmation",
578297
+ requiresIndependentEvidence: true,
578298
+ requiredCheck: "Rerun the original failing command path and capture a passing result as evidence."
578299
+ };
578300
+ }
578301
+ if (/(simulat|dry.?run|mock|mocked|virtual|paper|emulat)\b/.test(normalized)) {
578302
+ return {
578303
+ category: "reality",
578304
+ requiresIndependentEvidence: false,
578305
+ requiredCheck: "Mark as simulation-only unless paired with a grounded hardware/live execution claim."
578306
+ };
578307
+ }
577806
578308
  return {
577807
578309
  category: null,
577808
578310
  requiresIndependentEvidence: false,
577809
578311
  requiredCheck: ""
577810
578312
  };
577811
578313
  }
577812
- function detectExitCodeMisread(text2) {
577813
- void text2;
578314
+ function detectExitCodeMisread(input) {
578315
+ const source = typeof input === "string" ? {
578316
+ statement: input,
578317
+ command: "",
578318
+ output: "",
578319
+ exitCode: null,
578320
+ canonicalCommand: ""
578321
+ } : {
578322
+ statement: input.statement ?? "",
578323
+ command: input.command ?? input.canonicalCommand ?? "",
578324
+ output: input.output ?? "",
578325
+ exitCode: typeof input.exitCode === "number" && Number.isFinite(input.exitCode) ? input.exitCode : null,
578326
+ canonicalCommand: ""
578327
+ };
578328
+ const statement = normalizedEvidenceText(source.statement);
578329
+ const command = normalizedEvidenceText(source.command);
578330
+ const output = normalizedEvidenceText(source.output);
578331
+ const exitCode = source.exitCode;
578332
+ if (exitCode !== null && exitCode !== 0 && /\b(success|pass(?:ed|es)?|succeed(?:ed|s)?|ok|completed|done|finished|verified)\b/.test(statement)) {
578333
+ return true;
578334
+ }
578335
+ if (/\|\|\s*(true|:|exit\s+0)/.test(command))
578336
+ return true;
578337
+ if (/\bset\s*\+e\b/.test(command))
578338
+ return true;
578339
+ if (/;\s*\(\s*/.test(command))
578340
+ return true;
578341
+ if (command.includes("|") && !/\bset\s+-o\s+pipefail\b/.test(statement + " " + command)) {
578342
+ return true;
578343
+ }
578344
+ if (/\b\S+\s&\s*$/.test(command.trim()))
578345
+ return true;
578346
+ if (/\bexit(ed|ion)?\s+code\s*[1-9]\d*/.test(statement + " " + output)) {
578347
+ return true;
578348
+ }
577814
578349
  return false;
577815
578350
  }
577816
578351
  function auditCompletionClaims(claims) {
@@ -580965,8 +581500,8 @@ var init_evidenceLedger = __esm({
580965
581500
  }
580966
581501
  /**
580967
581502
  * Return a bounded, read-only projection for components that need to make a
580968
- * routing decision from observed workspace state (for example Feature Loop
580969
- * survey grounding). Callers cannot mutate ledger entries through this
581503
+ * routing decision from observed workspace state (for example claim-discovery
581504
+ * grounding). Callers cannot mutate ledger entries through this
580970
581505
  * result, preserving the ledger as the single freshness authority.
580971
581506
  */
580972
581507
  snapshot(maxEntries = 24) {
@@ -586883,7 +587418,7 @@ var init_longhaul_integration = __esm({
586883
587418
  }
586884
587419
  /**
586885
587420
  * WO-6 (spec §2.5): seed the locked contract from the planner's
586886
- * `LockedContract` at PLAN time. The Feature Loop calls this after the
587421
+ * `LockedContract` at PLAN time. The claim-discovery planner path calls this after the
586887
587422
  * planner emits its artefact, so the breaker's "regenerate from the locked
586888
587423
  * contract" guidance has a real target from the first boundary unit — without
586889
587424
  * waiting for coherent code to accumulate one. Idempotent + fault-tolerant.
@@ -589154,515 +589689,6 @@ var init_git_progress = __esm({
589154
589689
  }
589155
589690
  });
589156
589691
 
589157
- // packages/orchestrator/dist/featurePlanner.js
589158
- import fs7 from "node:fs";
589159
- import path9 from "node:path";
589160
- function classifyKind(survey) {
589161
- const files = survey.files ?? [];
589162
- const newSym = (survey.newSymbols ?? []).length;
589163
- const req3 = survey.request.toLowerCase();
589164
- if (/\b(investigat|why does|how does|trace|understand|root cause|diagnos|explain)\b/.test(req3) && newSym === 0 && files.length <= 2) {
589165
- return "investigation";
589166
- }
589167
- if (/\b(bug|fix|broken|regression|crash|incorrect|fails?|misbehav)/.test(req3) && newSym === 0) {
589168
- return "bugfix";
589169
- }
589170
- if (/\b(refactor|restructure|rename|clean up|simplif|migrate|consolidate)\b/.test(req3) && newSym === 0) {
589171
- return "refactor";
589172
- }
589173
- if (/\b(wir|connect|integrate|hook up|plumb|bridge|glue)\b/.test(req3) && files.length >= 2) {
589174
- return "wiring";
589175
- }
589176
- if (newSym > 0 || /\b(new|create|add|implement|build|introduce|scaffold)\b/.test(req3)) {
589177
- return "new-module";
589178
- }
589179
- return "new-module";
589180
- }
589181
- function guessKind(name10) {
589182
- if (/^(I[A-Z]|.*Interface|.*Contract|.*Spec|.*Event|.*Meta|.*Config|.*State)$/.test(name10)) {
589183
- return "interface";
589184
- }
589185
- if (/^(T|Type|.*Type)$/.test(name10))
589186
- return "type";
589187
- if (/^(E|Enum|.*Kind|.*Status|.*Mode)$/.test(name10))
589188
- return "enum";
589189
- if (/^[A-Z]/.test(name10))
589190
- return "class";
589191
- return "function";
589192
- }
589193
- function buildLockedContract(kind, survey) {
589194
- const symbols = [];
589195
- if (kind === "refactor") {
589196
- for (const name10 of survey.existingSymbols ?? []) {
589197
- symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
589198
- }
589199
- } else if (kind === "new-module") {
589200
- for (const name10 of survey.newSymbols ?? []) {
589201
- symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
589202
- }
589203
- }
589204
- return { symbols };
589205
- }
589206
- function decomposeFeature(survey, kind) {
589207
- const units = [];
589208
- const evidenceRefs = featureEvidenceRefs(survey);
589209
- const unresolvedQuestion = survey.unresolvedQuestions?.[0] ?? (evidenceRefs.length === 0 ? "Which current files, symbols, and tests govern this unit? Inspect them before proposing a mutation." : void 0);
589210
- const returnContract = "Return the direct result with cited observations, relevant/changed paths, verification or blocker, and the next parent decision.";
589211
- const withGrounding = (unit) => ({
589212
- ...unit,
589213
- evidenceRefs,
589214
- ...unresolvedQuestion ? { unresolvedQuestion } : {},
589215
- returnContract
589216
- });
589217
- if (kind === "new-module") {
589218
- const syms = survey.newSymbols ?? [];
589219
- if (syms.length === 0) {
589220
- units.push(withGrounding({
589221
- label: "Establish the module boundary and implement the evidenced unit",
589222
- size: "large",
589223
- detail: "Do not scaffold from the request alone. First identify the owning entry point, adjacent contract, and test surface from current evidence."
589224
- }));
589225
- } else {
589226
- for (const name10 of syms) {
589227
- units.push({
589228
- ...withGrounding({
589229
- label: `Implement ${name10} within its evidenced owner`,
589230
- size: "small",
589231
- detail: "Confirm the symbol's owning module and contract before editing; do not infer a file path from the feature label."
589232
- }),
589233
- expectedSymbols: [name10]
589234
- });
589235
- }
589236
- }
589237
- } else if (kind === "refactor") {
589238
- units.push(withGrounding({
589239
- label: "Refactor only the evidenced public surface",
589240
- size: survey.files.length > 1 ? "large" : "small"
589241
- }));
589242
- } else if (kind === "bugfix") {
589243
- units.push(withGrounding({
589244
- label: "Reproduce the evidenced failure, make the smallest justified fix, and verify it",
589245
- size: "small"
589246
- }));
589247
- } else if (kind === "wiring") {
589248
- units.push(withGrounding({
589249
- label: "Connect the evidenced module boundaries",
589250
- size: survey.files.length > 2 ? "large" : "small"
589251
- }));
589252
- } else {
589253
- units.push(withGrounding({
589254
- label: "Investigate the evidence gap and report the next justified action",
589255
- size: "small"
589256
- }));
589257
- }
589258
- return units;
589259
- }
589260
- function featureEvidenceRefs(survey) {
589261
- const declared = (survey.evidence ?? []).map((item) => item.ref.trim()).filter(Boolean).slice(0, 6);
589262
- if (declared.length > 0)
589263
- return declared;
589264
- return survey.files.map((file) => `survey:file:${file.path}`).filter(Boolean).slice(0, 6);
589265
- }
589266
- function buildFeatureUnitRequest(input) {
589267
- const evidence = (input.survey.evidence ?? []).filter((item) => !input.unit.evidenceRefs?.length || input.unit.evidenceRefs.includes(item.ref)).slice(0, 6);
589268
- const fallbackEvidence = evidence.length > 0 ? evidence : input.survey.files.slice(0, 6).map((file) => ({
589269
- ref: `survey:file:${file.path}`,
589270
- detail: `${file.path}${file.role ? ` — ${file.role}` : ""}`,
589271
- freshness: "unknown"
589272
- }));
589273
- const lines = [
589274
- "[FEATURE UNIT EVIDENCE BRIEF]",
589275
- `Parent request: ${input.parentRequest.slice(0, 900)}`,
589276
- `Requested unit: ${input.unit.label}`,
589277
- `Why now: this unit was selected from the current feature survey, not from a task label alone.`,
589278
- "Evidence:",
589279
- ...fallbackEvidence.length > 0 ? fallbackEvidence.map((item) => `- [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail.slice(0, 360)}`) : ["- No current code observation is available; discovery is required before mutation."],
589280
- input.unit.unresolvedQuestion ? `Open question: ${input.unit.unresolvedQuestion}` : null,
589281
- "Scope: stay within this unit and directly implicated code; do not broaden the feature without returning to the parent.",
589282
- `Return contract: ${input.unit.returnContract ?? "Return evidence, verification or blocker, and the next parent decision."}`,
589283
- "",
589284
- "Work protocol: inspect the cited files/contracts first. Only mutate after a fresh observation identifies the exact target; if the evidence does not support a target, report the gap instead of fabricating one."
589285
- ];
589286
- return lines.filter((line) => Boolean(line)).join("\n");
589287
- }
589288
- function renderSpecMarkdown(input) {
589289
- const { kind, survey, lockedContract, completionContract, decomposition, prose } = input;
589290
- const lines = [];
589291
- lines.push(`# Feature Plan — ${kind}`);
589292
- lines.push("");
589293
- lines.push(`**Request:** ${survey.request}`);
589294
- lines.push("");
589295
- lines.push(`**Node kind:** \`${kind}\` (selected by CLASSIFY over the survey signals)`);
589296
- lines.push("");
589297
- if (prose) {
589298
- lines.push(`## 1. Intent`);
589299
- lines.push("");
589300
- lines.push(prose.trim());
589301
- lines.push("");
589302
- }
589303
- lines.push(`## 2. Survey (codebase as-is)`);
589304
- lines.push("");
589305
- if (survey.files.length > 0) {
589306
- for (const f2 of survey.files) {
589307
- const refs = f2.lineRefs?.length ? `:${f2.lineRefs.join(",")}` : "";
589308
- lines.push(`- \`${f2.path}${refs}\`${f2.role ? ` — ${f2.role}` : ""}`);
589309
- }
589310
- } else {
589311
- lines.push("- (no files enumerated in survey)");
589312
- }
589313
- if (survey.evidence?.length) {
589314
- for (const item of survey.evidence.slice(0, 8)) {
589315
- lines.push(`- evidence [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail}`);
589316
- }
589317
- }
589318
- if (survey.unresolvedQuestions?.length) {
589319
- lines.push(`- unresolved: ${survey.unresolvedQuestions.join("; ")}`);
589320
- }
589321
- lines.push(`- new symbols: ${(survey.newSymbols ?? []).join(", ") || "none"}`);
589322
- lines.push(`- public surface changes: ${survey.publicSurfaceChanges ? "yes" : "no"}`);
589323
- lines.push(`- tests exist: ${survey.testsExist ? "yes" : "no"}`);
589324
- lines.push("");
589325
- lines.push(`## 3. Locked contract (executable gate)`);
589326
- lines.push("");
589327
- if (lockedContract.symbols.length === 0) {
589328
- lines.push("- (no locked symbols for this kind — disciplined but permissive)");
589329
- } else {
589330
- for (const s2 of lockedContract.symbols) {
589331
- lines.push(`- \`${s2.kind} ${s2.name}\``);
589332
- }
589333
- }
589334
- lines.push("");
589335
- lines.push(`## 4. Definition of done (CompletionContract)`);
589336
- lines.push("");
589337
- lines.push(`- goal: ${completionContract.goalSummary || "(none)"}`);
589338
- for (const p2 of completionContract.phases ?? []) {
589339
- lines.push(`- phase: ${p2.label}`);
589340
- }
589341
- lines.push("");
589342
- lines.push(`## 5. Decomposition (SPLIT seed)`);
589343
- lines.push("");
589344
- for (const u of decomposition) {
589345
- lines.push(`- [${u.size}] ${u.label}${u.expectedSymbols?.length ? ` (symbols: ${u.expectedSymbols.join(", ")})` : ""}${u.evidenceRefs?.length ? ` [evidence: ${u.evidenceRefs.join(", ")}]` : ""}`);
589346
- }
589347
- lines.push("");
589348
- lines.push(`## 6. Verification bar`);
589349
- lines.push("");
589350
- lines.push("- planner emits real artefacts (this file + locked contract + completion contract)");
589351
- lines.push("- approval gate blocks before any source edit");
589352
- lines.push("- WO-6 executor gate activates on locked symbols");
589353
- lines.push("- recursion + eviction keep context bounded");
589354
- lines.push("- scope token re-prompts on out-of-scope work");
589355
- lines.push("");
589356
- lines.push(`## 7. Handoff notes`);
589357
- lines.push("");
589358
- lines.push("- Compose, do not rebuild: this plan reuses spec-gate + completionContract primitives.");
589359
- lines.push("- Fail-closed: if planning errors, the run falls back to the general agentic loop.");
589360
- lines.push("");
589361
- return lines.join("\n");
589362
- }
589363
- async function planFeature(survey, options2 = {}) {
589364
- const kind = classifyKind(survey);
589365
- const lockedContract = buildLockedContract(kind, survey);
589366
- const completionContract = inferCompletionContractFromTexts([survey.request, ...survey.rawTexts ?? [], ...survey.signals ?? []], survey.request);
589367
- const decomposition = decomposeFeature(survey, kind);
589368
- let prose = "";
589369
- try {
589370
- if (options2.proseGenerator) {
589371
- prose = await options2.proseGenerator({ request: survey.request, kind, survey });
589372
- }
589373
- } catch {
589374
- prose = "";
589375
- }
589376
- const specMarkdown = renderSpecMarkdown({
589377
- kind,
589378
- survey,
589379
- lockedContract,
589380
- completionContract,
589381
- decomposition,
589382
- prose
589383
- });
589384
- return { kind, specMarkdown, lockedContract, completionContract, decomposition };
589385
- }
589386
- function persistPlannerArtefacts(rootId, artefact, stateDir) {
589387
- try {
589388
- const dir = path9.join(stateDir, "feature-tree", rootId);
589389
- fs7.mkdirSync(dir, { recursive: true });
589390
- fs7.writeFileSync(path9.join(dir, "spec.md"), artefact.specMarkdown, "utf8");
589391
- fs7.writeFileSync(path9.join(dir, "locked-contract.json"), JSON.stringify(artefact.lockedContract, null, 2), "utf8");
589392
- fs7.writeFileSync(path9.join(dir, "completion-contract.json"), JSON.stringify(artefact.completionContract, null, 2), "utf8");
589393
- } catch {
589394
- }
589395
- }
589396
- var init_featurePlanner = __esm({
589397
- "packages/orchestrator/dist/featurePlanner.js"() {
589398
- "use strict";
589399
- init_completionContract();
589400
- }
589401
- });
589402
-
589403
- // packages/orchestrator/dist/featureApprovalGate.js
589404
- function mintScopeToken(input) {
589405
- return {
589406
- rootId: input.rootId,
589407
- files: [...input.files ?? []],
589408
- symbols: input.lockedContract.symbols.map((s2) => s2.name),
589409
- nodeKinds: input.nodeKinds ?? ["new-module", "refactor", "bugfix", "wiring", "investigation"],
589410
- depthCap: input.depthCap
589411
- };
589412
- }
589413
- function isWithinScope(input) {
589414
- const { token } = input;
589415
- if (typeof input.depth === "number" && input.depth > token.depthCap) {
589416
- return false;
589417
- }
589418
- if (input.nodeKind && !token.nodeKinds.includes(input.nodeKind)) {
589419
- return false;
589420
- }
589421
- if (input.newSymbol && !token.symbols.includes(input.newSymbol)) {
589422
- return false;
589423
- }
589424
- if (input.file) {
589425
- const file = input.file;
589426
- const allowed = token.files.some((f2) => {
589427
- if (f2 === file)
589428
- return true;
589429
- if (f2.endsWith("/") && file.startsWith(f2))
589430
- return true;
589431
- if (f2.includes("*") && globMatch(f2, file))
589432
- return true;
589433
- return false;
589434
- });
589435
- if (!allowed)
589436
- return false;
589437
- }
589438
- return true;
589439
- }
589440
- function globMatch(pattern, value2) {
589441
- const re = new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
589442
- return re.test(value2);
589443
- }
589444
- async function requestApproval(req3, ask2, options2 = {}) {
589445
- let decision2;
589446
- try {
589447
- const raw = await ask2(req3);
589448
- decision2 = raw === "approve" || raw === "edit" || raw === "reject" ? raw : "reject";
589449
- } catch {
589450
- decision2 = "reject";
589451
- }
589452
- if (decision2 === "approve") {
589453
- const token = mintScopeToken({
589454
- rootId: req3.rootId,
589455
- lockedContract: req3.lockedContract,
589456
- decomposition: req3.decomposition,
589457
- depthCap: req3.depthCap,
589458
- files: options2.files,
589459
- nodeKinds: options2.nodeKinds
589460
- });
589461
- return { decision: decision2, token };
589462
- }
589463
- return { decision: decision2 };
589464
- }
589465
- var init_featureApprovalGate = __esm({
589466
- "packages/orchestrator/dist/featureApprovalGate.js"() {
589467
- "use strict";
589468
- }
589469
- });
589470
-
589471
- // packages/orchestrator/dist/featureNode.js
589472
- import fs8 from "node:fs";
589473
- import path10 from "node:path";
589474
- function treePath(stateDir, rootId) {
589475
- return path10.join(stateDir, "feature-tree", `${rootId}.json`);
589476
- }
589477
- function saveFeatureTree(stateDir, rootId, nodes) {
589478
- try {
589479
- const file = treePath(stateDir, rootId);
589480
- fs8.mkdirSync(path10.dirname(file), { recursive: true });
589481
- fs8.writeFileSync(file, JSON.stringify(nodes, null, 2), "utf8");
589482
- } catch {
589483
- }
589484
- }
589485
- function loadFeatureTree(stateDir, rootId) {
589486
- try {
589487
- const file = treePath(stateDir, rootId);
589488
- if (!fs8.existsSync(file))
589489
- return null;
589490
- const raw = JSON.parse(fs8.readFileSync(file, "utf8"));
589491
- return raw && typeof raw === "object" ? raw : null;
589492
- } catch {
589493
- return null;
589494
- }
589495
- }
589496
- function newNodeId(depth, seed) {
589497
- const h = String(Math.abs(hashString2(seed)) % 1e9).padStart(9, "0");
589498
- return `fn-d${depth}-${h}`;
589499
- }
589500
- function hashString2(s2) {
589501
- let h = 0;
589502
- for (let i2 = 0; i2 < s2.length; i2++)
589503
- h = h * 31 + s2.charCodeAt(i2) | 0;
589504
- return h;
589505
- }
589506
- async function evictNode(node, ctx3, transcript) {
589507
- try {
589508
- await runTodoChunker({
589509
- inputs: {
589510
- todoId: node.id,
589511
- todoContent: node.request,
589512
- turnRange: [0, 0],
589513
- transcript: transcript || node.request,
589514
- toolCalls: [],
589515
- workingDirectory: ctx3.workingDirectory,
589516
- sessionId: ctx3.sessionId
589517
- },
589518
- callable: ctx3.summarizer ?? (async () => "")
589519
- });
589520
- } catch {
589521
- }
589522
- }
589523
- async function execUnit(unit, node, ctx3, contract, maxRegenerate) {
589524
- let result = await ctx3.executeUnit(unit, node);
589525
- if (!result.ok)
589526
- return false;
589527
- const expected = unit.expectedSymbols ?? [];
589528
- if (expected.length === 0) {
589529
- return true;
589530
- }
589531
- for (let attempt = 0; attempt <= maxRegenerate; attempt++) {
589532
- if (!result.path || result.source === void 0)
589533
- return false;
589534
- const verdict = evaluateExecutorStep({
589535
- unit: { path: result.path, source: result.source },
589536
- contract,
589537
- expectedSymbols: expected
589538
- });
589539
- if (verdict.decision === "accept")
589540
- return true;
589541
- if (verdict.decision === "replan")
589542
- return false;
589543
- result = await ctx3.executeUnit(unit, node);
589544
- if (!result.ok)
589545
- return false;
589546
- }
589547
- return false;
589548
- }
589549
- async function runFeatureNode(node, ctx3, options2, tree2 = {}) {
589550
- const maxRegenerate = options2.maxRegenerate ?? 2;
589551
- tree2[node.id] = node;
589552
- try {
589553
- const artefact = await planFeature(options2.survey, {
589554
- proseGenerator: options2.proseGenerator
589555
- });
589556
- node.kind = artefact.kind;
589557
- if (ctx3.onPlan) {
589558
- try {
589559
- await ctx3.onPlan(artefact);
589560
- } catch {
589561
- }
589562
- }
589563
- persistPlannerArtefacts(ctx3.rootId, artefact, ctx3.stateDir);
589564
- const mustAsk = node.depth === 0 || !node.scopeToken;
589565
- if (mustAsk && ctx3.askApproval) {
589566
- node.status = "awaiting_approval";
589567
- const outcome = await requestApproval({
589568
- rootId: ctx3.rootId,
589569
- request: node.request,
589570
- specMarkdown: artefact.specMarkdown,
589571
- lockedContract: artefact.lockedContract,
589572
- decomposition: artefact.decomposition,
589573
- depthCap: ctx3.depthCap
589574
- }, ctx3.askApproval, { files: options2.survey.files.map((f2) => f2.path) });
589575
- if (outcome.decision !== "approve") {
589576
- node.status = outcome.decision === "edit" ? "planned" : "rejected";
589577
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589578
- return node;
589579
- }
589580
- node.scopeToken = outcome.token;
589581
- }
589582
- node.status = "approved";
589583
- node.status = "executing";
589584
- let allOk = true;
589585
- for (const unit of artefact.decomposition) {
589586
- if (unit.size === "large" && node.depth < ctx3.depthCap) {
589587
- const childId = newNodeId(node.depth + 1, unit.label + node.id);
589588
- const childRequest = buildFeatureUnitRequest({
589589
- unit,
589590
- parentRequest: node.request,
589591
- survey: options2.survey
589592
- });
589593
- const child = {
589594
- id: childId,
589595
- parentId: node.id,
589596
- depth: node.depth + 1,
589597
- request: childRequest,
589598
- kind: artefact.kind,
589599
- status: "planned",
589600
- scopeToken: node.scopeToken,
589601
- children: []
589602
- };
589603
- node.children.push(childId);
589604
- const childSurvey = {
589605
- ...options2.survey,
589606
- request: child.request
589607
- };
589608
- const childCtx = {
589609
- ...ctx3,
589610
- // children inherit the token; re-prompt only if they exceed scope
589611
- askApproval: (req3) => isWithinScope({
589612
- token: node.scopeToken,
589613
- depth: node.depth + 1,
589614
- nodeKind: artefact.kind
589615
- }) ? "approve" : ctx3.askApproval(req3)
589616
- };
589617
- const res = await runFeatureNode(child, childCtx, { ...options2, survey: childSurvey }, tree2);
589618
- if (res.status !== "completed")
589619
- allOk = false;
589620
- await evictNode(child, ctx3, child.request);
589621
- } else {
589622
- const ok3 = await execUnit(unit, node, ctx3, artefact.lockedContract, maxRegenerate);
589623
- if (!ok3)
589624
- allOk = false;
589625
- }
589626
- }
589627
- if (allOk) {
589628
- node.status = "completed";
589629
- } else {
589630
- node.status = "failed";
589631
- }
589632
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589633
- return node;
589634
- } catch {
589635
- if (ctx3.runGeneralLoop) {
589636
- await ctx3.runGeneralLoop(node.request);
589637
- node.status = "completed";
589638
- } else {
589639
- node.status = "failed";
589640
- }
589641
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589642
- return node;
589643
- }
589644
- }
589645
- function createRootFeatureNode(request) {
589646
- return {
589647
- id: newNodeId(0, request),
589648
- parentId: null,
589649
- depth: 0,
589650
- request,
589651
- kind: "new-module",
589652
- status: "planned",
589653
- children: []
589654
- };
589655
- }
589656
- var init_featureNode = __esm({
589657
- "packages/orchestrator/dist/featureNode.js"() {
589658
- "use strict";
589659
- init_featurePlanner();
589660
- init_featureApprovalGate();
589661
- init_spec_gate();
589662
- init_todo_context_chunker();
589663
- }
589664
- });
589665
-
589666
589692
  // packages/orchestrator/dist/preflightSnapshot.js
589667
589693
  var preflightSnapshot_exports = {};
589668
589694
  __export(preflightSnapshot_exports, {
@@ -590781,6 +590807,142 @@ function stripShellQuotedSegments(command) {
590781
590807
  }
590782
590808
  return out;
590783
590809
  }
590810
+ function extractClaimPathFragments(text2) {
590811
+ const out = [];
590812
+ const pathPattern = /\b(?:[\w.-]+\/[\w./-]+(?:\.[A-Za-z0-9]+)?|[\w.-]+\.[A-Za-z0-9]+)\b/g;
590813
+ for (const match of text2.matchAll(pathPattern)) {
590814
+ const value2 = sanitizeDelegationText(String(match[0] ?? ""), 260).trim();
590815
+ if (!value2)
590816
+ continue;
590817
+ out.push(value2);
590818
+ }
590819
+ return [...new Set(out)];
590820
+ }
590821
+ function normalizeClaimPathSignal(raw) {
590822
+ const normalized = raw.replace(/["'`]+/g, "").replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/").trim().toLowerCase();
590823
+ if (!normalized)
590824
+ return "";
590825
+ if (normalized.length < 4)
590826
+ return "";
590827
+ if (normalized.includes(".."))
590828
+ return "";
590829
+ if (/[\\s]/.test(normalized))
590830
+ return "";
590831
+ return normalized;
590832
+ }
590833
+ function isLikelyPathSignal(value2) {
590834
+ if (!value2)
590835
+ return false;
590836
+ return value2.includes("/") || /\.[a-z0-9]+$/i.test(value2);
590837
+ }
590838
+ function collectClaimPathSignals(text2) {
590839
+ const direct = extractClaimPathFragments(text2).map((value2) => normalizeClaimPathSignal(value2)).filter(isLikelyPathSignal);
590840
+ const quoted = [...text2.matchAll(/["'`](.*?)["'`]/g)].map((match) => normalizeClaimPathSignal(String(match[1] ?? ""))).filter((value2) => isLikelyPathSignal(value2));
590841
+ return [.../* @__PURE__ */ new Set([...direct, ...quoted])];
590842
+ }
590843
+ function matchHintToInventoryPath(path16, hint) {
590844
+ const normalizedPath = normalizeClaimPathSignal(path16);
590845
+ const normalizedHint = normalizeClaimPathSignal(hint);
590846
+ if (!normalizedPath || !normalizedHint)
590847
+ return false;
590848
+ if (normalizedPath === normalizedHint)
590849
+ return true;
590850
+ if (normalizedPath.endsWith(`/${normalizedHint}`))
590851
+ return true;
590852
+ if (normalizedPath.endsWith(normalizedHint))
590853
+ return true;
590854
+ if (normalizedHint.includes("/") && normalizedPath.includes(normalizedHint))
590855
+ return true;
590856
+ const base3 = normalizedPath.split("/").at(-1) ?? "";
590857
+ return base3 === normalizedHint;
590858
+ }
590859
+ function claimDiscoveryFallbackCandidates(files, maxCandidates) {
590860
+ const ranked = [];
590861
+ const nowMs = Date.now();
590862
+ const maxAgeMs = 30 * 24 * 60 * 60 * 1e3;
590863
+ for (const raw of files) {
590864
+ const rawPath = String(raw.path ?? "").trim();
590865
+ if (!rawPath || rawPath.startsWith(".omnius/"))
590866
+ continue;
590867
+ const normalized = rawPath.replace(/\s+/g, " ").trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/").toLowerCase();
590868
+ if (normalized.length < 4 || normalized.includes(".."))
590869
+ continue;
590870
+ const chunks = normalized.split("/").filter(Boolean);
590871
+ const depth = chunks.length || 1;
590872
+ const reasons = [];
590873
+ let score = 0;
590874
+ score += Math.max(1, 12 - Math.min(depth, 10));
590875
+ reasons.push("generic workspace proximity");
590876
+ if (raw.bytes !== void 0) {
590877
+ if (raw.bytes > 5e5)
590878
+ score -= 3;
590879
+ else if (raw.bytes > 8e4)
590880
+ score -= 1;
590881
+ if (raw.bytes > 5e5)
590882
+ reasons.push("large artifact");
590883
+ else if (raw.bytes > 8e4)
590884
+ reasons.push("moderate artifact");
590885
+ else
590886
+ reasons.push("light payload");
590887
+ }
590888
+ if (raw.mtimeMs !== void 0 && raw.mtimeMs > 0) {
590889
+ const age = nowMs - raw.mtimeMs;
590890
+ if (age >= 0 && age < maxAgeMs) {
590891
+ score += 2;
590892
+ reasons.push("recently modified");
590893
+ } else if (age < 0) {
590894
+ score += 1;
590895
+ reasons.push("fresh metadata");
590896
+ } else {
590897
+ reasons.push("older artifact");
590898
+ }
590899
+ }
590900
+ const pathSignal = chunks.join("/");
590901
+ if (!pathSignal)
590902
+ continue;
590903
+ ranked.push({
590904
+ path: pathSignal,
590905
+ score,
590906
+ reasons: [...new Set(reasons)].slice(0, 3)
590907
+ });
590908
+ }
590909
+ ranked.sort((left, right) => right.score !== left.score ? right.score - left.score : left.path.localeCompare(right.path));
590910
+ const fallback = [];
590911
+ for (const entry of ranked) {
590912
+ if (fallback.length >= maxCandidates)
590913
+ break;
590914
+ const canonical2 = entry.path.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\.\//, "").trim().toLowerCase();
590915
+ if (canonical2.length < 4 || canonical2.includes(".."))
590916
+ continue;
590917
+ if (fallback.some((candidate) => candidate.path === canonical2))
590918
+ continue;
590919
+ fallback.push({
590920
+ path: canonical2,
590921
+ reasons: entry.reasons.length > 0 ? entry.reasons : ["generic workspace candidate"]
590922
+ });
590923
+ }
590924
+ return fallback;
590925
+ }
590926
+ function extractClaimTaskTokens(text2) {
590927
+ return String(text2 ?? "").toLowerCase().replace(/["'`]/g, " ").replace(/[^\w./-]+/g, " ").split(/\s+/).map((value2) => value2.trim()).filter((value2) => value2.length >= 4 && value2.length <= 80 && /[a-z0-9]/i.test(value2)).slice(0, 80);
590928
+ }
590929
+ function isMeaningfulClaimTaskToken(token) {
590930
+ if (!token)
590931
+ return false;
590932
+ const normalized = token.toLowerCase();
590933
+ if (normalized.length < 4 || normalized.length > 80)
590934
+ return false;
590935
+ if (!/[a-z0-9]/i.test(normalized))
590936
+ return false;
590937
+ if (CLAIM_TASK_STOPWORDS.has(normalized))
590938
+ return false;
590939
+ return true;
590940
+ }
590941
+ function chunkHasSymbolMatch(token, text2) {
590942
+ const haystack = text2.toLowerCase().replace(/[^a-z0-9]+/g, " ");
590943
+ const tokens = haystack.split(" ").filter(Boolean);
590944
+ return tokens.includes(token);
590945
+ }
590784
590946
  function isCompilerLikeVerifierCommand(command) {
590785
590947
  const normalized = command.toLowerCase();
590786
590948
  return /\b(?:pio|platformio|tsc|gcc|g\+\+|clang\+\+?|clang|cargo\s+(?:build|check)|go\s+(?:build|test)|javac|gradle|mvn|msbuild|dotnet\s+build|python(?:3)?\s+-m\s+(?:py_compile|compileall)|mypy|pyright)\b/.test(normalized);
@@ -591523,7 +591685,7 @@ function classifyThinkOutcome(raw) {
591523
591685
  }
591524
591686
  return null;
591525
591687
  }
591526
- var PRESERVE_MODEL_VISIBLE_HISTORY, TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, LEGACY_ACTION_REASON_KEYS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
591688
+ var PRESERVE_MODEL_VISIBLE_HISTORY, TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, LEGACY_ACTION_REASON_KEYS, CLAIM_TASK_STOPWORDS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
591527
591689
  var init_agenticRunner = __esm({
591528
591690
  "packages/orchestrator/dist/agenticRunner.js"() {
591529
591691
  "use strict";
@@ -591605,8 +591767,6 @@ var init_agenticRunner = __esm({
591605
591767
  init_prompt_cache();
591606
591768
  init_compile_error_fix_loop();
591607
591769
  init_git_progress();
591608
- init_featurePlanner();
591609
- init_featureNode();
591610
591770
  PRESERVE_MODEL_VISIBLE_HISTORY = /* @__PURE__ */ Symbol("omnius.preserveModelVisibleHistory");
591611
591771
  TOOL_SUBSETS = {
591612
591772
  web: ["web_search", "web_fetch", "web_crawl"],
@@ -591633,6 +591793,79 @@ var init_agenticRunner = __esm({
591633
591793
  };
591634
591794
  TOOL_AUTO_DEMOTE_TURNS = 10;
591635
591795
  LEGACY_ACTION_REASON_KEYS = /* @__PURE__ */ new Set(["action_reason", "actionReason"]);
591796
+ CLAIM_TASK_STOPWORDS = /* @__PURE__ */ new Set([
591797
+ "this",
591798
+ "that",
591799
+ "these",
591800
+ "those",
591801
+ "there",
591802
+ "where",
591803
+ "from",
591804
+ "with",
591805
+ "what",
591806
+ "when",
591807
+ "then",
591808
+ "help",
591809
+ "please",
591810
+ "request",
591811
+ "about",
591812
+ "their",
591813
+ "would",
591814
+ "could",
591815
+ "should",
591816
+ "might",
591817
+ "issue",
591818
+ "issues",
591819
+ "bug",
591820
+ "problem",
591821
+ "problems",
591822
+ "task",
591823
+ "tasks",
591824
+ "run",
591825
+ "build",
591826
+ "make",
591827
+ "need",
591828
+ "needs",
591829
+ "also",
591830
+ "only",
591831
+ "same",
591832
+ "other",
591833
+ "code",
591834
+ "file",
591835
+ "files",
591836
+ "repo",
591837
+ "project",
591838
+ "workspace",
591839
+ "read",
591840
+ "fix",
591841
+ "add",
591842
+ "remove",
591843
+ "create",
591844
+ "review",
591845
+ "check",
591846
+ "report",
591847
+ "inspect",
591848
+ "update",
591849
+ "implement",
591850
+ "setup",
591851
+ "install",
591852
+ "deploy",
591853
+ "run",
591854
+ "get",
591855
+ "set",
591856
+ "open",
591857
+ "close",
591858
+ "start",
591859
+ "stop",
591860
+ "turn",
591861
+ "off",
591862
+ "on",
591863
+ "enable",
591864
+ "disable",
591865
+ "add",
591866
+ "new",
591867
+ "old"
591868
+ ]);
591636
591869
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
591637
591870
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
591638
591871
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -591930,8 +592163,6 @@ var init_agenticRunner = __esm({
591930
592163
  _wideExplorationCooldownUntilTurn = -1;
591931
592164
  /** REG-44: how many times the stuck detector has fired (for adaptive cooldown). */
591932
592165
  _reg44FireCount = 0;
591933
- /** Guard against re-entering the feature loop. */
591934
- _inFeatureLoop = false;
591935
592166
  // REG-45: sticky cross-turn escalation. The dispatch-time reflection
591936
592167
  // surface (REG-26) only fires when the agent re-emits the exact same
591937
592168
  // failed stem. If the agent thrashes on OTHER tools (wide-exploration
@@ -592051,6 +592282,7 @@ var init_agenticRunner = __esm({
592051
592282
  */
592052
592283
  _completionCaveat = null;
592053
592284
  _completionLedger = null;
592285
+ _claimDiscoveryInitialized = false;
592054
592286
  _staleEditFamilies = /* @__PURE__ */ new Map();
592055
592287
  /** Semantic retry counter for blocked full-file writes (payload-independent). */
592056
592288
  _blockedFullWriteAttempts = /* @__PURE__ */ new Map();
@@ -593424,7 +593656,9 @@ ${parts.join("\n")}
593424
593656
  success: input.status === "completed",
593425
593657
  output: `terminal_receipt=${record.id}
593426
593658
  marker=${markerPath}
593427
- evidence=${record.evidenceIds.join(",") || "none"}`
593659
+ evidence=${record.evidenceIds.join(",") || "none"}
593660
+ command_receipts=${record.commandReceipts.length}
593661
+ ` + (record.commandReceipts.length > 0 ? `command_receipts_summary=${record.commandReceipts.map((entry) => `${entry.canonicalCommand || entry.command || "n/a"}:${entry.exitCode}`).join(" | ")}` : "command_receipts_summary=none")
593428
593662
  });
593429
593663
  commitTerminalTrajectoryProjection(stateDir, record, input.trajectoryPayload);
593430
593664
  const committed = {
@@ -593516,6 +593750,7 @@ evidence=${record.evidenceIds.join(",") || "none"}`
593516
593750
  disableAdversaryCritic,
593517
593751
  disableStepCritic: disableAdversaryCritic,
593518
593752
  modelTier: options2?.modelTier ?? "large",
593753
+ claimDiscovery: options2?.claimDiscovery,
593519
593754
  referenceContractModules: options2?.referenceContractModules ?? [],
593520
593755
  contextWindowSize: options2?.contextWindowSize ?? 0,
593521
593756
  recursionDepth: options2?.recursionDepth ?? 0,
@@ -593567,16 +593802,29 @@ evidence=${record.evidenceIds.join(",") || "none"}`
593567
593802
  const loaded = loadDeliveryCoverageManifest(this.authoritativeWorkingDirectory());
593568
593803
  if (!loaded)
593569
593804
  return null;
593805
+ for (const entry of this._evidenceLedger.snapshot(200)) {
593806
+ this._evidenceLedger.validateFreshness(entry.path, _pathResolve(this.authoritativeWorkingDirectory(), entry.path));
593807
+ }
593570
593808
  const evidence = this._completionLedger?.evidence.map((entry) => ({
593571
593809
  id: entry.id,
593572
593810
  success: entry.success,
593573
593811
  receipt: entry.receipt
593574
593812
  })) ?? [];
593575
- const evaluated = evaluateDeliveryCoverage(loaded.manifest, evidence);
593813
+ const sourceObservations = this._evidenceLedger.snapshot(200).map((entry) => ({
593814
+ path: entry.path,
593815
+ contentHash: entry.contentHash,
593816
+ fidelity: entry.fidelity,
593817
+ stale: entry.stale
593818
+ }));
593819
+ const evaluated = evaluateDeliveryCoverage(loaded.manifest, evidence, sourceObservations);
593820
+ const firstInspectionGap = evaluated.gaps.find((gap) => gap.code === "missing_inspection" || gap.code === "stale_inspection" || gap.code === "missing_contradiction_check");
593576
593821
  return {
593577
593822
  rendered: renderDeliveryCoverageState(evaluated, loaded.path),
593578
593823
  gaps: evaluated.gaps.map((gap) => `[${gap.code}] ${gap.claimId}: ${gap.detail}`),
593579
- completionReady: evaluated.completionReady
593824
+ completionReady: evaluated.completionReady,
593825
+ ...firstInspectionGap ? { nextInspection: firstInspectionGap.detail } : {},
593826
+ sourcePath: loaded.path,
593827
+ evaluation: evaluated
593580
593828
  };
593581
593829
  }
593582
593830
  _modelCapabilityProfile() {
@@ -593608,6 +593856,24 @@ evidence=${record.evidenceIds.join(",") || "none"}`
593608
593856
  this._completionLedger = {
593609
593857
  ...this._completionLedger,
593610
593858
  unresolved: [...retained, ...unresolved],
593859
+ deliveryCoverage: {
593860
+ manifestHash: coverage.evaluation.manifestHash,
593861
+ sourcePath: coverage.sourcePath,
593862
+ evaluatedAtIso: (/* @__PURE__ */ new Date()).toISOString(),
593863
+ claims: coverage.evaluation.claimStates.map((claim) => ({
593864
+ id: claim.id,
593865
+ state: claim.state,
593866
+ attainedState: claim.attainedState,
593867
+ missingInspectionIds: [...claim.missingInspectionIds],
593868
+ missingContradictionCheckIds: [...claim.missingContradictionCheckIds],
593869
+ missingAcceptanceIds: [...claim.missingAcceptanceIds]
593870
+ })),
593871
+ gaps: coverage.evaluation.gaps.map((gap) => ({
593872
+ claimId: gap.claimId,
593873
+ code: gap.code,
593874
+ detail: gap.detail
593875
+ }))
593876
+ },
593611
593877
  status: coverage.completionReady && unresolved.length === 0 ? this._completionLedger.status : "incomplete_verification",
593612
593878
  updatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
593613
593879
  };
@@ -594362,10 +594628,10 @@ ${read3.content}`;
594362
594628
  if (!branchDerived && !partialMaterialization && path16) {
594363
594629
  try {
594364
594630
  const canonicalBody = input.result.output || input.output;
594365
- const canonicalPath = this._normalizeEvidencePath(path16);
594631
+ const canonicalPath2 = this._normalizeEvidencePath(path16);
594366
594632
  const sourceRevision = typeof input.result.beforeHash === "string" ? input.result.beforeHash : _createHash("sha256").update(canonicalBody).digest("hex");
594367
594633
  const stored = this._artifactStore().put({
594368
- path: canonicalPath,
594634
+ path: canonicalPath2,
594369
594635
  revision: sourceRevision,
594370
594636
  content: canonicalBody,
594371
594637
  ranges: [{
@@ -594405,13 +594671,13 @@ ${read3.content}`;
594405
594671
  ledger.linkDependency({ sourceRecordId: artifact.id, targetRecordId: result.id, relation: "derived_from", requiredForActiveWork: true });
594406
594672
  ledger.linkDependency({ sourceRecordId: action.id, targetRecordId: artifact.id, relation: "requires", requiredForActiveWork: true });
594407
594673
  if (!branchDerived && !partialMaterialization && path16) {
594408
- const canonicalPath = this._normalizeEvidencePath(path16);
594409
- const previous = this._contextMemoryArtifactByPath.get(canonicalPath);
594674
+ const canonicalPath2 = this._normalizeEvidencePath(path16);
594675
+ const previous = this._contextMemoryArtifactByPath.get(canonicalPath2);
594410
594676
  const currentHash = typeof input.result.beforeHash === "string" ? input.result.beforeHash : void 0;
594411
594677
  if (previous && previous.epoch === epoch && previous.contentHash && currentHash && previous.contentHash !== currentHash) {
594412
594678
  ledger.supersedeArtifact(previous.recordId, artifact.id);
594413
594679
  }
594414
- this._contextMemoryArtifactByPath.set(canonicalPath, {
594680
+ this._contextMemoryArtifactByPath.set(canonicalPath2, {
594415
594681
  recordId: artifact.id,
594416
594682
  contentHash: currentHash,
594417
594683
  ...canonicalArtifactReference ? { artifactReference: canonicalArtifactReference } : {},
@@ -596912,7 +597178,7 @@ ${extras.join("\n")}`;
596912
597178
  const paths = args["edits"].map((edit) => edit && typeof edit === "object" ? edit["path"] : null).filter((p3) => typeof p3 === "string" && p3.trim().length > 0);
596913
597179
  return [...new Set(paths)];
596914
597180
  }
596915
- const p2 = args?.["path"] ?? args?.["file_path"] ?? args?.["file"] ?? args?.["filename"] ?? args?.["filepath"] ?? args?.["filePath"];
597181
+ const p2 = args?.["path"] ?? args?.["file_path"] ?? args?.["file"] ?? args?.["filename"] ?? args?.["filepath"] ?? args?.["filePath"] ?? args?.["input"] ?? args?.["target"];
596916
597182
  return typeof p2 === "string" && p2.trim().length > 0 ? [p2.trim()] : [];
596917
597183
  }
596918
597184
  _isRealProjectMutation(toolName, result) {
@@ -597053,6 +597319,9 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597053
597319
  metrics: input.result.completionEvidenceMetrics,
597054
597320
  receipt
597055
597321
  });
597322
+ if (this._completionLedger?.claimDiscovery) {
597323
+ this._refreshClaimDiscoveryStateFromEvidence();
597324
+ }
597056
597325
  if (realFileMutation && realMutationPaths.length > 0) {
597057
597326
  for (const filePath of realMutationPaths) {
597058
597327
  this._completionLedger = recordCompletionEvidence(this._completionLedger, {
@@ -597069,6 +597338,50 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597069
597338
  }
597070
597339
  this._saveCompletionLedgerSafe();
597071
597340
  }
597341
+ _refreshClaimDiscoveryStateFromEvidence() {
597342
+ if (!this._completionLedger?.claimDiscovery)
597343
+ return;
597344
+ const state = this._completionLedger.claimDiscovery;
597345
+ const evidenceHandles = state.evidenceHandles ?? [];
597346
+ const survivingBlockers = state.survivingBlockers ?? [];
597347
+ const unresolvedQuestions = state.unresolvedQuestions ?? [];
597348
+ const openDeltas = state.openDeltas ?? [];
597349
+ const resolved = claimDiscoveryResolvedHandles(this._completionLedger, state);
597350
+ const unresolvedEvidence = evidenceHandles.filter((handle2) => !resolved.includes(handle2));
597351
+ const unresolvedHandleSet = new Set(unresolvedEvidence);
597352
+ const unresolvedOpenDeltas = openDeltas.filter((delta) => {
597353
+ const normalizedDeltaPath = this._normalizeEvidencePath(delta.path).replace(/^\/+/, "");
597354
+ const handle2 = `workspace:${normalizedDeltaPath}`;
597355
+ return unresolvedHandleSet.has(handle2);
597356
+ });
597357
+ const hasBlockers = survivingBlockers.length > 0;
597358
+ const hasCandidates = state.candidatePaths.length > 0;
597359
+ const hasOpenQuestions = unresolvedQuestions.length > 0;
597360
+ const hasOpenEvidence = unresolvedEvidence.length > 0;
597361
+ let status;
597362
+ if (!hasCandidates) {
597363
+ status = hasBlockers || hasOpenQuestions ? "blocked" : "skipped";
597364
+ } else if (hasOpenEvidence || hasOpenQuestions || hasBlockers) {
597365
+ status = hasOpenQuestions || hasBlockers ? "blocked" : "active";
597366
+ } else {
597367
+ status = "complete";
597368
+ }
597369
+ const updated = {
597370
+ ...this._completionLedger,
597371
+ claimDiscovery: {
597372
+ ...state,
597373
+ openDeltas: unresolvedOpenDeltas,
597374
+ resolvedEvidenceHandles: resolved,
597375
+ evidenceHandles,
597376
+ survivingBlockers,
597377
+ unresolvedQuestions,
597378
+ status
597379
+ }
597380
+ };
597381
+ this._completionLedger = updated;
597382
+ this._saveCompletionLedgerSafe();
597383
+ return updated.claimDiscovery;
597384
+ }
597072
597385
  _completionArtifactHashes(paths) {
597073
597386
  const unique3 = [...new Set(paths.map((path16) => this._normalizeEvidencePath(path16)).filter(Boolean))].slice(0, 20);
597074
597387
  const out = [];
@@ -597821,15 +598134,18 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597821
598134
  }
597822
598135
  const timeoutMs = parseInt(process.env["OMNIUS_COMPLETION_VERIFY_TIMEOUT_MS"] || "180000", 10) || 18e4;
597823
598136
  const wd = this._workingDirectory || process.cwd();
598137
+ const hasPipe = cmd.includes("|");
598138
+ const startedAtIso = (/* @__PURE__ */ new Date()).toISOString();
597824
598139
  this.emit({
597825
598140
  type: "status",
597826
598141
  content: `completion verify gate: running '${cmd}' (cwd=${wd})`,
597827
598142
  turn,
597828
598143
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
597829
598144
  });
597830
- const { exitCode, outTail } = await new Promise((resolve84) => {
598145
+ const { exitCode, outTail, timedOut, finishedAtIso } = await new Promise((resolve84) => {
597831
598146
  const chunks = [];
597832
598147
  let settled = false;
598148
+ let hitTimeout = false;
597833
598149
  const child = _spawn(cmd, {
597834
598150
  cwd: wd,
597835
598151
  shell: true,
@@ -597845,6 +598161,7 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597845
598161
  child.stderr?.on("data", onData);
597846
598162
  const killTimer = setTimeout(() => {
597847
598163
  try {
598164
+ hitTimeout = true;
597848
598165
  child.kill("SIGKILL");
597849
598166
  } catch {
597850
598167
  }
@@ -597855,11 +598172,31 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597855
598172
  return;
597856
598173
  settled = true;
597857
598174
  clearTimeout(killTimer);
597858
- resolve84({ exitCode: code8, outTail: chunks.join("").slice(-4e3) });
598175
+ resolve84({
598176
+ exitCode: code8,
598177
+ outTail: chunks.join("").slice(-4e3),
598178
+ timedOut: hitTimeout,
598179
+ finishedAtIso: (/* @__PURE__ */ new Date()).toISOString()
598180
+ });
597859
598181
  };
597860
598182
  child.on("error", () => finish(1));
597861
598183
  child.on("close", (code8) => finish(code8 ?? 1));
597862
598184
  });
598185
+ const commandReceipt = {
598186
+ schema: "omnius.command-evidence-receipt.v1",
598187
+ command: cmd,
598188
+ canonicalCommand: "",
598189
+ cwd: wd,
598190
+ exitCode,
598191
+ pipefail: hasPipe,
598192
+ timedOut,
598193
+ startedAtIso,
598194
+ finishedAtIso,
598195
+ artifactHashes: this._completionArtifactHashes([
598196
+ ...this._taskState.modifiedFiles.keys()
598197
+ ])
598198
+ };
598199
+ commandReceipt.canonicalCommand = canonicalVerificationIdentity(cmd, commandReceipt) ?? normalizeShellCommand(cmd) ?? cmd;
597863
598200
  if (this._completionLedger) {
597864
598201
  this._completionLedger = recordCompletionEvidence(this._completionLedger, {
597865
598202
  kind: "tool_result",
@@ -597867,9 +598204,11 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597867
598204
  success: exitCode === 0,
597868
598205
  summary: `completion verify command exited ${exitCode}: ${cmd}
597869
598206
  ${outTail || "(no output captured)"}`,
598207
+ receipt: commandReceipt,
597870
598208
  role: "verification",
597871
598209
  family: "completion_verify"
597872
598210
  });
598211
+ this._refreshClaimDiscoveryResolvedHandles();
597873
598212
  this._saveCompletionLedgerSafe();
597874
598213
  }
597875
598214
  const compileGuidance = this._observeCompileVerifierResult({
@@ -597927,7 +598266,8 @@ ${compileGuidance}` : ""
597927
598266
  const _newClaims = deriveClaimsFromProposedText({
597928
598267
  text: proposedSummary,
597929
598268
  source: "task_complete_summary",
597930
- existing: this._completionLedger.proposedClaims
598269
+ existing: this._completionLedger.proposedClaims,
598270
+ workspaceInventory: this._completionLedger.claimDiscovery?.boundedInventory
597931
598271
  });
597932
598272
  if (_newClaims.length > 0) {
597933
598273
  this._completionLedger = addCompletionClaims(this._completionLedger, _newClaims);
@@ -597937,7 +598277,10 @@ ${compileGuidance}` : ""
597937
598277
  try {
597938
598278
  const _audit = auditCompletionClaims(this._completionLedger.proposedClaims.map((c9) => ({
597939
598279
  text: c9.text,
597940
- status: c9.status
598280
+ status: c9.status,
598281
+ riskCategory: c9.riskCategory === "unknown" || c9.riskCategory === "coverage" ? null : c9.riskCategory,
598282
+ requiresIndependentEvidence: c9.requiresIndependentEvidence,
598283
+ requiredCheck: c9.requiredCheck
597941
598284
  })));
597942
598285
  if (!_audit.ok) {
597943
598286
  const _checks = _audit.blockers.map((b) => `• [${b.category}] "${b.claim}" → ${b.requiredCheck}`).join("\n");
@@ -598161,8 +598504,9 @@ ${_checks}`
598161
598504
  verdict: "approve",
598162
598505
  rationale: result.verdict.rationale
598163
598506
  });
598164
- this._saveCompletionLedgerSafe();
598165
598507
  }
598508
+ this._saveCompletionLedgerSafe();
598509
+ this._refreshClaimDiscoveryResolvedHandles();
598166
598510
  this._lastBackwardPassCritique = null;
598167
598511
  return { proceed: true };
598168
598512
  }
@@ -598232,6 +598576,9 @@ ${_checks}`
598232
598576
  }
598233
598577
  return { proceed: false, feedback };
598234
598578
  }
598579
+ _refreshClaimDiscoveryResolvedHandles() {
598580
+ this._refreshClaimDiscoveryStateFromEvidence();
598581
+ }
598235
598582
  /**
598236
598583
  * WO-META-TRACK — Hannover-style turn-counter reminder.
598237
598584
  *
@@ -600229,7 +600576,8 @@ ${String(concreteGoal).replace(/\s+/g, " ").trim().slice(0, 1200)}` : null
600229
600576
  tier: this.options.modelTier ?? "large",
600230
600577
  includeCore: false,
600231
600578
  includePhase: true,
600232
- includeExplicit: false
600579
+ includeExplicit: false,
600580
+ includeDeliverySurface: Boolean(deliveryCoverageBlock)
600233
600581
  });
600234
600582
  const phaseSkillGuidance = buildPhaseSkillGuidance({
600235
600583
  repoRoot: this.authoritativeWorkingDirectory(),
@@ -602029,12 +602377,12 @@ ${notice}`;
602029
602377
  this._emitSteeringLifecycle(record, gatesOldPlan ? `admitted at turn ${turn}; old-plan actions are gated pending structured reconciliation` : `admitted at turn ${turn}; awaiting structured reconciliation`);
602030
602378
  }
602031
602379
  }
602032
- _canonicalReadEvidencePayload(canonicalPath, contentHash2) {
602033
- const evidence = this._evidenceLedger.get(canonicalPath);
602380
+ _canonicalReadEvidencePayload(canonicalPath2, contentHash2) {
602381
+ const evidence = this._evidenceLedger.get(canonicalPath2);
602034
602382
  if (evidence && !evidence.stale && evidence.contentHash === contentHash2 && evidence.fidelity === "full" && this._mustHonorExplicitFullFileRead(Buffer.byteLength(evidence.content, "utf8"), evidence.content.split("\n").length, this._branchRoutingContextWindow())) {
602035
602383
  return evidence.content;
602036
602384
  }
602037
- const branch = this._branchEvidenceByPath.get(canonicalPath);
602385
+ const branch = this._branchEvidenceByPath.get(canonicalPath2);
602038
602386
  if (branch && branch.contentHash === contentHash2 && branch.taskEpoch === this._taskEpoch && branch.contractComplete) {
602039
602387
  return branch.output;
602040
602388
  }
@@ -602115,6 +602463,7 @@ ${notice}`;
602115
602463
  runId: this.currentArtifactRunId(),
602116
602464
  goal: record.content
602117
602465
  }) : null;
602466
+ this._claimDiscoveryInitialized = false;
602118
602467
  if (this._completionLedger) {
602119
602468
  this._completionLedger.taskEpoch = this._taskEpoch;
602120
602469
  }
@@ -602485,17 +602834,17 @@ The steering reconciliation was emitted this turn. Wait for the next model decis
602485
602834
  }
602486
602835
  }
602487
602836
  _evictInlineReadArtifacts(messages2, path16, contentHash2, reason) {
602488
- const canonicalPath = this._normalizeEvidencePath(path16);
602837
+ const canonicalPath2 = this._normalizeEvidencePath(path16);
602489
602838
  let evicted = 0;
602490
602839
  for (const [callId, artifact] of this._inlineReadArtifacts) {
602491
- if (artifact.path !== canonicalPath || artifact.contentHash !== contentHash2) {
602840
+ if (artifact.path !== canonicalPath2 || artifact.contentHash !== contentHash2) {
602492
602841
  continue;
602493
602842
  }
602494
602843
  const message2 = messages2.find((candidate) => candidate.role === "tool" && candidate.tool_call_id === artifact.callId);
602495
602844
  if (message2) {
602496
602845
  message2.content = [
602497
602846
  "[FULL_FILE_READ_EVICTED]",
602498
- `path=${canonicalPath}`,
602847
+ `path=${canonicalPath2}`,
602499
602848
  `sha256=${contentHash2}`,
602500
602849
  `reason=${reason}`,
602501
602850
  "The full body was deliberately removed after a verified evidence extraction. Use the newer anchored extraction result; re-read only if the file changes or a distinct range is required."
@@ -602598,15 +602947,15 @@ The steering reconciliation was emitted this turn. Wait for the next model decis
602598
602947
  purpose: typeof input.args["purpose"] === "string" ? input.args["purpose"] : void 0
602599
602948
  });
602600
602949
  const contractFingerprint = _createHash("sha256").update(JSON.stringify(branchBrief.discoveryContract ?? branchBrief)).digest("hex").slice(0, 20);
602601
- const canonicalPath = this._normalizeEvidencePath(rawPath);
602602
- const branchRequestId = `branch:${this._taskEpoch}:${_createHash("sha256").update(`${canonicalPath}|${fullHash}|${offset ?? 0}:${limit ?? "EOF"}|${contractFingerprint}`).digest("hex").slice(0, 20)}`;
602603
- const cacheKey = `${this._taskEpoch}|${canonicalPath}|${fullHash}|${offset ?? 0}:${limit ?? "EOF"}|${contractFingerprint}`;
602950
+ const canonicalPath2 = this._normalizeEvidencePath(rawPath);
602951
+ const branchRequestId = `branch:${this._taskEpoch}:${_createHash("sha256").update(`${canonicalPath2}|${fullHash}|${offset ?? 0}:${limit ?? "EOF"}|${contractFingerprint}`).digest("hex").slice(0, 20)}`;
602952
+ const cacheKey = `${this._taskEpoch}|${canonicalPath2}|${fullHash}|${offset ?? 0}:${limit ?? "EOF"}|${contractFingerprint}`;
602604
602953
  const cached2 = this._branchEvidenceCache.get(cacheKey);
602605
602954
  if (cached2?.contractComplete) {
602606
602955
  const fingerprint2 = this._buildToolFingerprint(input.toolName, input.args);
602607
602956
  const rehydrated = this._rehydrateResolvedReadEvidence({
602608
602957
  fingerprint: fingerprint2,
602609
- canonicalPath,
602958
+ canonicalPath: canonicalPath2,
602610
602959
  contentHash: fullHash,
602611
602960
  payload: cached2.output,
602612
602961
  turn: input.turn
@@ -602619,7 +602968,7 @@ The steering reconciliation was emitted this turn. Wait for the next model decis
602619
602968
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
602620
602969
  });
602621
602970
  if (explicitExtraction) {
602622
- this._evictInlineReadArtifacts(input.messages, canonicalPath, fullHash, "verified_branch_extract_cache");
602971
+ this._evictInlineReadArtifacts(input.messages, canonicalPath2, fullHash, "verified_branch_extract_cache");
602623
602972
  }
602624
602973
  return {
602625
602974
  success: true,
@@ -602637,7 +602986,7 @@ The steering reconciliation was emitted this turn. Wait for the next model decis
602637
602986
  schema: "omnius.branch-evidence.v1",
602638
602987
  requestId: cached2.requestId,
602639
602988
  taskEpoch: this._taskEpoch,
602640
- path: canonicalPath,
602989
+ path: canonicalPath2,
602641
602990
  contentHash: fullHash,
602642
602991
  sourceRange: {
602643
602992
  startLine: startIndex + 1,
@@ -602705,7 +603054,7 @@ ${suffix}`.slice(0, outputBudgetChars);
602705
603054
  }
602706
603055
  this._branchEvidenceCache.set(cacheKey, {
602707
603056
  output,
602708
- path: canonicalPath,
603057
+ path: canonicalPath2,
602709
603058
  contentHash: fullHash,
602710
603059
  sourceBytes: stat9.size,
602711
603060
  createdAt: Date.now(),
@@ -602720,7 +603069,7 @@ ${suffix}`.slice(0, outputBudgetChars);
602720
603069
  searchRounds: ev.provenance.searchRounds.length
602721
603070
  }
602722
603071
  });
602723
- this._branchEvidenceByPath.set(canonicalPath, {
603072
+ this._branchEvidenceByPath.set(canonicalPath2, {
602724
603073
  output,
602725
603074
  contentHash: fullHash,
602726
603075
  mtimeMs: stat9.mtimeMs,
@@ -602730,12 +603079,12 @@ ${suffix}`.slice(0, outputBudgetChars);
602730
603079
  unresolvedRecoveries: ev.requirementCoverage.filter((coverage) => coverage.status === "unresolved").map((coverage) => `${coverage.id}: ${coverage.recovery ?? "narrow recovery required"}`)
602731
603080
  });
602732
603081
  if (explicitExtraction) {
602733
- const evicted = this._evictInlineReadArtifacts(input.messages, canonicalPath, fullHash, "verified_branch_extract");
603082
+ const evicted = this._evictInlineReadArtifacts(input.messages, canonicalPath2, fullHash, "verified_branch_extract");
602734
603083
  if (evicted > 0) {
602735
603084
  this.emit({
602736
603085
  type: "status",
602737
603086
  toolName: input.toolName,
602738
- content: `Full read context evicted after verified branch extraction: ${canonicalPath} sha256=${fullHash.slice(0, 12)} artifacts=${evicted}`,
603087
+ content: `Full read context evicted after verified branch extraction: ${canonicalPath2} sha256=${fullHash.slice(0, 12)} artifacts=${evicted}`,
602739
603088
  turn: input.turn,
602740
603089
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
602741
603090
  });
@@ -602765,7 +603114,7 @@ ${suffix}`.slice(0, outputBudgetChars);
602765
603114
  schema: "omnius.branch-evidence.v1",
602766
603115
  requestId: branchRequestId,
602767
603116
  taskEpoch: this._taskEpoch,
602768
- path: canonicalPath,
603117
+ path: canonicalPath2,
602769
603118
  contentHash: fullHash,
602770
603119
  sourceRange: {
602771
603120
  startLine: startIndex + 1,
@@ -603144,111 +603493,210 @@ ${rawTask}`;
603144
603493
  return next;
603145
603494
  }
603146
603495
  /**
603147
- * Feature Loop used to classify and split from the raw user sentence. Build
603148
- * a small, model-selected survey first instead: the model sees only an
603149
- * inventory of paths (not invented contents), chooses candidate files, and
603150
- * names the facts that still require file_read before any unit can mutate.
603151
- * Returning null deliberately falls back to the ordinary tool loop rather
603152
- * than recreating the old task-label-only Feature Loop.
603496
+ * Claim-discovery uses task + bounded workspace inventory before any mutation.
603497
+ * It remains task-centered and product-agnostic: no protocol-specific
603498
+ * heuristics, no model-inferred domain taxonomy, no filename-category
603499
+ * inference. Candidate grounding is deterministic from task + bounded inventory
603500
+ * signals only.
603153
603501
  */
603154
- async _resolveFeatureSurvey(task, context2, turn) {
603155
- if (process.env["OMNIUS_FEATURE_SURVEY_GROUNDING"] === "0")
603156
- return null;
603502
+ async _resolveClaimDiscoverySurvey(task, turn) {
603503
+ if (process.env["OMNIUS_FEATURE_SURVEY_GROUNDING"] === "0") {
603504
+ return claimDiscoveryStateFromSurvey({
603505
+ request: task,
603506
+ boundedInventory: {
603507
+ root: this.authoritativeWorkingDirectory(),
603508
+ files: [],
603509
+ dirs: [],
603510
+ truncated: true,
603511
+ maxFiles: 0,
603512
+ maxDirs: 0,
603513
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603514
+ },
603515
+ candidatePaths: [],
603516
+ pathReasons: {},
603517
+ unresolvedQuestions: [],
603518
+ survivingBlockers: [
603519
+ "Claim discovery is currently disabled by OMNIUS_FEATURE_SURVEY_GROUNDING=0."
603520
+ ],
603521
+ requiresEvidence: false
603522
+ });
603523
+ }
603157
603524
  const root = this.authoritativeWorkingDirectory();
603158
- let workspaceFiles = [];
603159
- try {
603160
- workspaceFiles = scanWorkspace({ root, maxFiles: 320, maxDirs: 800 }).files.map((file) => ({ rel: file.rel, bytes: file.bytes }));
603525
+ const maxFiles = Math.max(80, Math.min(420, Number.parseInt(process.env["OMNIUS_CLAIM_DISCOVERY_MAX_FILES"] || "240", 10) || 240));
603526
+ const maxDirs = Math.max(60, Math.min(1200, Number.parseInt(process.env["OMNIUS_CLAIM_DISCOVERY_MAX_DIRS"] || "300", 10) || 300));
603527
+ let boundedInventory = null;
603528
+ try {
603529
+ const workspace = scanWorkspace({ root, maxFiles, maxDirs });
603530
+ const files = workspace.files.slice(0, maxFiles).map((file) => ({
603531
+ path: file.rel,
603532
+ bytes: file.bytes,
603533
+ mtimeMs: file.mtimeMs
603534
+ })).filter((file) => !file.path.startsWith(".omnius/"));
603535
+ boundedInventory = {
603536
+ root,
603537
+ files,
603538
+ dirs: workspace.dirs.slice(0, maxDirs).map((dir) => dir.rel),
603539
+ truncated: workspace.truncated,
603540
+ maxFiles,
603541
+ maxDirs,
603542
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603543
+ };
603161
603544
  } catch {
603162
- return null;
603163
- }
603164
- if (workspaceFiles.length === 0)
603165
- return null;
603166
- const allowedPaths = new Set(workspaceFiles.map((file) => file.rel));
603167
- const ledgerEvidence = this._evidenceLedger.snapshot(12).map((entry) => ({
603168
- ref: `read:${entry.path}`,
603169
- detail: `${entry.path} was read at turn ${entry.lastReadTurn}${entry.stale ? " and is now stale" : ""}.`,
603170
- freshness: entry.stale ? "stale" : "fresh"
603171
- }));
603172
- const inventory = workspaceFiles.slice(0, 320).map((file) => `${file.rel} (${file.bytes} bytes)`).join("\n");
603173
- const prompt = [
603174
- "You are Omnius's feature survey grounder. Return JSON only; do not provide chain-of-thought.",
603175
- "You have file-existence metadata, not source contents. Select only candidate paths from the provided inventory and state what must be inspected before any mutation. Do not claim code behavior, APIs, or test results from a filename.",
603176
- "Schema:",
603177
- JSON.stringify({
603178
- candidate_paths: ["exact allowed relative path, 1-8 items"],
603179
- path_reasons: { "path": "why this is a candidate, based only on request/inventory" },
603180
- unresolved_questions: ["specific source fact to inspect before edit"],
603181
- new_symbols: ["only explicitly requested symbols, if any"],
603182
- existing_symbols: ["only symbols named in supplied context, if any"],
603183
- tests_exist: false,
603184
- public_surface_changes: false
603185
- }),
603186
- `Task:
603187
- ${sanitizeDelegationText(task, 1400)}`,
603188
- context2 ? `Parent context (may be stale; verify):
603189
- ${sanitizeDelegationText(context2, 1200)}` : "",
603190
- ledgerEvidence.length ? `Fresh/stale reads already observed:
603191
- ${ledgerEvidence.map((item) => `- [${item.freshness}] ${item.ref}: ${item.detail}`).join("\n")}` : "No source files have been read in this run yet.",
603192
- `Allowed workspace inventory:
603193
- ${inventory}`
603194
- ].filter(Boolean).join("\n\n");
603195
- try {
603196
- this._emitModelResolutionTelemetry("feature_survey_grounding", turn);
603197
- const backend = this._auxInferenceBackend({
603198
- dumpStage: "feature_survey_grounding"
603199
- });
603200
- const response = await backend.chatCompletion({
603201
- messages: [
603202
- {
603203
- role: "system",
603204
- content: "Return only valid JSON matching the requested schema. Never invent a path or infer file content from its name."
603205
- },
603206
- { role: "user", content: prompt }
603545
+ return claimDiscoveryStateFromSurvey({
603546
+ request: task,
603547
+ boundedInventory: {
603548
+ root,
603549
+ files: [],
603550
+ dirs: [],
603551
+ truncated: true,
603552
+ maxFiles,
603553
+ maxDirs,
603554
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603555
+ },
603556
+ candidatePaths: [],
603557
+ pathReasons: {},
603558
+ unresolvedQuestions: [
603559
+ "Workspace scan failed for bounded inventory grounding; retry with explicit target paths."
603207
603560
  ],
603208
- tools: [],
603209
- temperature: 0.1,
603210
- maxTokens: 900,
603211
- timeoutMs: Math.max(5e3, Math.min(this.options.requestTimeoutMs, 25e3)),
603212
- think: false
603561
+ survivingBlockers: [
603562
+ "Claim discovery cannot anchor evidence without a successful workspace inventory scan."
603563
+ ],
603564
+ requiresEvidence: false
603213
603565
  });
603214
- const raw = response.choices?.[0]?.message?.content ?? "";
603215
- const json = raw.match(/```(?:json)?\s*([\s\S]*?)```/)?.[1] ?? raw.match(/\{[\s\S]*\}/)?.[0] ?? "";
603216
- const parsed = JSON.parse(json);
603217
- const requestedPaths = Array.isArray(parsed["candidate_paths"]) ? parsed["candidate_paths"].map((value2) => String(value2).trim()).filter((value2) => allowedPaths.has(value2)).slice(0, 8) : [];
603218
- if (requestedPaths.length === 0)
603219
- return null;
603220
- const reasons = parsed["path_reasons"] && typeof parsed["path_reasons"] === "object" ? parsed["path_reasons"] : {};
603221
- const stringList3 = (value2, cap, maxChars) => Array.isArray(value2) ? value2.map((item) => sanitizeDelegationText(item, maxChars)).filter(Boolean).slice(0, cap) : [];
603222
- const selectedEvidence2 = requestedPaths.map((file) => ({
603223
- ref: `workspace:${file}`,
603224
- detail: sanitizeDelegationText(reasons[file], 280) || "Selected from the workspace inventory; source contents remain uninspected.",
603225
- freshness: "unknown"
603226
- }));
603227
- const unresolvedQuestions = stringList3(parsed["unresolved_questions"], 6, 260);
603228
- if (unresolvedQuestions.length === 0) {
603229
- unresolvedQuestions.push("Read the selected source and its nearest tests/callers to establish the exact implementation contract before editing.");
603230
- }
603231
- return {
603566
+ }
603567
+ if (!boundedInventory || boundedInventory.files.length === 0) {
603568
+ return claimDiscoveryStateFromSurvey({
603232
603569
  request: task,
603233
- files: requestedPaths.map((path16) => ({
603234
- path: path16,
603235
- role: sanitizeDelegationText(reasons[path16], 180) || "candidate selected from workspace inventory"
603236
- })),
603237
- signals: [
603238
- "Feature survey candidates were generated from the current workspace inventory.",
603239
- ...unresolvedQuestions
603570
+ boundedInventory: boundedInventory ?? {
603571
+ root,
603572
+ files: [],
603573
+ dirs: [],
603574
+ truncated: true,
603575
+ maxFiles,
603576
+ maxDirs,
603577
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603578
+ },
603579
+ candidatePaths: [],
603580
+ pathReasons: {},
603581
+ unresolvedQuestions: [
603582
+ "Bounded workspace inventory was empty; provide concrete target artifacts before claiming completion."
603240
603583
  ],
603241
- rawTexts: [task, context2 ?? ""],
603242
- evidence: [...ledgerEvidence, ...selectedEvidence2].slice(0, 14),
603243
- unresolvedQuestions,
603244
- newSymbols: stringList3(parsed["new_symbols"], 8, 120),
603245
- existingSymbols: stringList3(parsed["existing_symbols"], 8, 120),
603246
- testsExist: parsed["tests_exist"] === true,
603247
- publicSurfaceChanges: parsed["public_surface_changes"] === true
603248
- };
603249
- } catch {
603250
- return null;
603584
+ survivingBlockers: ["No bounded inventory files were discoverable."],
603585
+ requiresEvidence: false
603586
+ });
603587
+ }
603588
+ const boundedInventoryPaths = boundedInventory.files.map((file) => file.path);
603589
+ const allowedPaths = new Set(boundedInventoryPaths);
603590
+ const pathReasons = /* @__PURE__ */ Object.create(null);
603591
+ const normalizedTask = sanitizeDelegationText(task, 1500);
603592
+ const taskTokens = extractClaimTaskTokens(task);
603593
+ const meaningfulTaskTokens = taskTokens.filter(isMeaningfulClaimTaskToken);
603594
+ const explicitPathHints = collectClaimPathSignals(task).map((token) => token.toLowerCase()).slice(0, 80);
603595
+ const unmatchedHints = new Set(explicitPathHints);
603596
+ const scored = [];
603597
+ for (const path16 of boundedInventoryPaths) {
603598
+ const lowerPath = path16.toLowerCase();
603599
+ const lowerBase = (path16.split("/").at(-1) ?? "").toLowerCase();
603600
+ const chunks = lowerPath.split("/").filter(Boolean);
603601
+ let score = 0;
603602
+ const reasons = [];
603603
+ for (const hint of explicitPathHints) {
603604
+ if (!matchHintToInventoryPath(path16, hint))
603605
+ continue;
603606
+ unmatchedHints.delete(hint);
603607
+ score += 120;
603608
+ reasons.push(`explicit path hint "${hint}" matches path`);
603609
+ }
603610
+ for (const token of meaningfulTaskTokens) {
603611
+ const lowerToken = token.toLowerCase();
603612
+ if (lowerToken.length < 4)
603613
+ continue;
603614
+ if (chunks.some((chunk) => chunk === lowerToken)) {
603615
+ score += 40;
603616
+ reasons.push(`segment token match (${lowerToken})`);
603617
+ } else if (lowerPath.includes(lowerToken)) {
603618
+ score += 14;
603619
+ reasons.push(`path includes task token (${lowerToken})`);
603620
+ } else if (chunkHasSymbolMatch(lowerToken, lowerBase)) {
603621
+ score += 6;
603622
+ reasons.push(`base symbol overlap (${lowerToken})`);
603623
+ }
603624
+ }
603625
+ if (score > 0) {
603626
+ scored.push({
603627
+ path: path16,
603628
+ score,
603629
+ reasons: [...new Set(reasons)].slice(0, 3)
603630
+ });
603631
+ }
603251
603632
  }
603633
+ scored.sort((left, right) => right.score !== left.score ? right.score - left.score : left.path.localeCompare(right.path));
603634
+ const rankedCandidates = scored.filter((entry) => entry.score > 0).map((entry) => entry.path).slice(0, 12);
603635
+ const explicitCandidates = explicitPathHints.flatMap((token) => boundedInventoryPaths.filter((path16) => matchHintToInventoryPath(path16, token))).filter((path16) => allowedPaths.has(path16)).slice(0, 12);
603636
+ const candidateSeeds = explicitCandidates.length > 0 ? explicitCandidates : rankedCandidates;
603637
+ const candidatePaths = [.../* @__PURE__ */ new Set([...candidateSeeds, ...rankedCandidates])].slice(0, 8);
603638
+ const shouldUseFallbackCandidates = explicitPathHints.length === 0 && candidatePaths.length === 0;
603639
+ const fallbackCandidates = shouldUseFallbackCandidates ? claimDiscoveryFallbackCandidates(boundedInventory.files, Math.max(4, Math.min(8, maxFiles ? Math.min(8, maxFiles) : 8))) : [];
603640
+ let finalCandidatePaths = candidatePaths.length > 0 ? candidatePaths : fallbackCandidates.map((entry) => entry.path);
603641
+ if (candidatePaths.length === 0 && fallbackCandidates.length > 0) {
603642
+ for (const candidate of fallbackCandidates) {
603643
+ if (!pathReasons[candidate.path]) {
603644
+ pathReasons[candidate.path] = candidate.reasons.join("; ");
603645
+ }
603646
+ }
603647
+ }
603648
+ if (finalCandidatePaths.length === 0 && boundedInventory.files.length > 0) {
603649
+ const boundedPaths = boundedInventory.files.map((file) => String(file.path ?? "")).map((path16) => path16.trim()).filter((path16) => path16.length >= 4 && path16.length <= 800).filter((path16) => !path16.startsWith(".omnius/"));
603650
+ const candidateWithDir = boundedPaths.filter((path16) => path16.includes("/")).slice(0, 4);
603651
+ finalCandidatePaths = (candidateWithDir.length > 0 ? candidateWithDir : boundedPaths).slice(0, 4);
603652
+ for (const candidate of finalCandidatePaths) {
603653
+ if (!pathReasons[candidate]) {
603654
+ pathReasons[candidate] = "selected from bounded inventory fallback";
603655
+ }
603656
+ }
603657
+ }
603658
+ if (finalCandidatePaths.length === 0) {
603659
+ const hasUnmatchedHints = unmatchedHints.size > 0;
603660
+ const unresolvedQuestions2 = hasUnmatchedHints ? [
603661
+ normalizedTask.length < 5 ? "Task text is too short to anchor evidence safely." : `No grounded candidate source path was identified for explicit task hints (${[...unmatchedHints].slice(0, 4).join(", ")}).`,
603662
+ "Read from declared artifacts before claiming completion."
603663
+ ] : [];
603664
+ const survivingBlockers2 = unmatchedHints.size > 0 ? [
603665
+ `No bounded inventory artifact matched explicit task hints: ${[...unmatchedHints].slice(0, 4).join(", ")}`
603666
+ ] : [];
603667
+ return claimDiscoveryStateFromSurvey({
603668
+ request: task,
603669
+ boundedInventory,
603670
+ candidatePaths: [],
603671
+ pathReasons: {},
603672
+ unresolvedQuestions: unresolvedQuestions2,
603673
+ survivingBlockers: survivingBlockers2,
603674
+ requiresEvidence: explicitPathHints.length > 0
603675
+ });
603676
+ }
603677
+ for (const candidate of finalCandidatePaths) {
603678
+ const details = scored.find((entry) => entry.path === candidate);
603679
+ if (!pathReasons[candidate]) {
603680
+ pathReasons[candidate] = details && details.reasons.length > 0 ? details.reasons.join("; ") : unmatchedHints.size > 0 ? "selected from explicit task hints plus inventory" : meaningfulTaskTokens.length === 0 ? "selected from bounded inventory fallback" : "selected from bounded request signals and inventory";
603681
+ }
603682
+ }
603683
+ const unresolvedQuestions = unmatchedHints.size > 0 ? [
603684
+ `Unresolved explicit task hints remain unmatched: ${[...unmatchedHints].slice(0, 3).join(", ")}.`,
603685
+ "If task intent changed, restate target artifacts in the user message."
603686
+ ] : [];
603687
+ const survivingBlockers = unmatchedHints.size > 0 ? [
603688
+ `Unmatched explicit task hints: ${[...unmatchedHints].slice(0, 3).join(", ")}`
603689
+ ] : [];
603690
+ const shouldRequireEvidence = finalCandidatePaths.length > 0 && (explicitPathHints.length > 0 || rankedCandidates.length > 0);
603691
+ return claimDiscoveryStateFromSurvey({
603692
+ request: task,
603693
+ boundedInventory,
603694
+ candidatePaths: finalCandidatePaths,
603695
+ pathReasons,
603696
+ unresolvedQuestions,
603697
+ survivingBlockers,
603698
+ requiresEvidence: shouldRequireEvidence
603699
+ });
603252
603700
  }
603253
603701
  /**
603254
603702
  * Rebuild the one current checkpoint at the context boundary. This shared
@@ -603575,6 +604023,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
603575
604023
  this._completionIncompleteVerification = null;
603576
604024
  this._completionCaveat = null;
603577
604025
  this._completionLedger = null;
604026
+ this._claimDiscoveryInitialized = false;
603578
604027
  this._focusTerminalLedgerRecorded = false;
603579
604028
  this._resetTaskScopedVerifierState();
603580
604029
  this._staleEditFamilies.clear();
@@ -603875,6 +604324,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
603875
604324
  runId: this._activeRunId || this._sessionId,
603876
604325
  goal: userGoal
603877
604326
  });
604327
+ this._claimDiscoveryInitialized = false;
603878
604328
  this._completionLedger.taskEpoch = this._taskEpoch;
603879
604329
  } else {
603880
604330
  this._completionContract = null;
@@ -604531,6 +604981,72 @@ ${dynamicProjectContext}`
604531
604981
  messages2.push({ role: "system", content: feedback });
604532
604982
  return true;
604533
604983
  };
604984
+ const holdDeliveryCoverageTaskComplete = (turn) => {
604985
+ const coverage = this._deliveryCoverageState();
604986
+ if (!coverage || coverage.completionReady)
604987
+ return false;
604988
+ this._reconcileDeliveryCoverageForCompletion();
604989
+ this._saveCompletionLedgerSafe();
604990
+ const gaps = coverage.gaps.slice(0, 6);
604991
+ const feedback = [
604992
+ "[COMPLETION BLOCKED — delivery claim evidence incomplete]",
604993
+ "A declared delivery claim cannot be promoted beyond its current evidence state.",
604994
+ "Open claim deltas:",
604995
+ ...gaps.length > 0 ? gaps.map((gap) => ` - ${gap}`) : [" - delivery coverage is not completion-ready"],
604996
+ "",
604997
+ coverage.nextInspection ? `Smallest next observation: ${coverage.nextInspection}` : "Run the missing canonical acceptance command or mark the claim blocked with its real prerequisite.",
604998
+ "Do not replace a missing source inspection with a grep/listing, partial read, or prose summary."
604999
+ ].join("\n");
605000
+ lastCompletionGateReason = gaps.join("; ") || "delivery claim evidence incomplete";
605001
+ lastCompletionGateFeedback = feedback;
605002
+ lastCompletionGateCode = "delivery_coverage";
605003
+ messages2.push({ role: "system", content: feedback });
605004
+ this.emit({
605005
+ type: "status",
605006
+ content: `task_complete held by delivery coverage gate: ${lastCompletionGateReason.slice(0, 360)}`,
605007
+ turn,
605008
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
605009
+ });
605010
+ return true;
605011
+ };
605012
+ const holdClaimDiscoveryTaskComplete = (turn) => {
605013
+ const ledger = this._completionLedger;
605014
+ if (!ledger?.claimDiscovery)
605015
+ return false;
605016
+ this._refreshClaimDiscoveryStateFromEvidence();
605017
+ const state = this._completionLedger?.claimDiscovery;
605018
+ if (!state)
605019
+ return false;
605020
+ const evidenceHandles = state.evidenceHandles ?? [];
605021
+ const unresolvedQuestions = state.unresolvedQuestions ?? [];
605022
+ const resolved = claimDiscoveryResolvedHandles(ledger, state);
605023
+ const unresolved = evidenceHandles.filter((handle2) => !resolved.includes(handle2));
605024
+ const blockers = state.survivingBlockers ?? [];
605025
+ const openDeltas = state.openDeltas ?? [];
605026
+ const hasOpenDiscoveryWork = unresolved.length > 0 || blockers.length > 0 || unresolvedQuestions.length > 0;
605027
+ const shouldHold = (state.status === "active" || state.status === "blocked") && hasOpenDiscoveryWork && state.requiresEvidence !== false;
605028
+ if (!shouldHold) {
605029
+ return false;
605030
+ }
605031
+ const feedback = [
605032
+ "[COMPLETION BLOCKED — evidence discovery incomplete]",
605033
+ `Open claim-discovery deltas: ${openDeltas.map((item) => `${item.path} :: ${item.reason}`).join(" | ") || "none"}`,
605034
+ `Outstanding evidence handles: ${unresolved.join(" | ") || "none"}`,
605035
+ ...blockers.length > 0 ? [`Surviving blockers: ${blockers.join(" | ")}`] : [],
605036
+ state.unresolvedQuestions.length > 0 ? `Outstanding question(s): ${state.unresolvedQuestions.slice(0, 4).join(" | ")}` : ""
605037
+ ].filter(Boolean).join("\n");
605038
+ lastCompletionGateReason = unresolved.length > 0 ? `claim discovery evidence pending (${unresolved.length})` : "claim discovery is still waiting on blockers/questions";
605039
+ lastCompletionGateFeedback = feedback;
605040
+ lastCompletionGateCode = "claim_discovery";
605041
+ messages2.push({ role: "system", content: feedback });
605042
+ this.emit({
605043
+ type: "status",
605044
+ content: `task_complete held by claim discovery gate: ${lastCompletionGateReason}`,
605045
+ turn,
605046
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
605047
+ });
605048
+ return true;
605049
+ };
604534
605050
  const completionHoldEscapeMax = (() => {
604535
605051
  const raw = Number(process.env["OMNIUS_COMPLETION_HOLD_MAX"]);
604536
605052
  return Number.isFinite(raw) && raw >= 1 ? Math.floor(raw) : 3;
@@ -604579,7 +605095,7 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
604579
605095
  lastCompletionGateCode = "";
604580
605096
  return true;
604581
605097
  }
604582
- const held = holdCompileFixLoopTaskComplete(turn) || holdUnresolvedVerificationTaskComplete(turn) || holdNoProgressTaskComplete(args, turn) || holdProvenanceTaskComplete(args, turn);
605098
+ const held = holdDeliveryCoverageTaskComplete(turn) || holdCompileFixLoopTaskComplete(turn) || holdUnresolvedVerificationTaskComplete(turn) || holdNoProgressTaskComplete(args, turn) || holdProvenanceTaskComplete(args, turn) || holdClaimDiscoveryTaskComplete(turn);
604583
605099
  if (!held) {
604584
605100
  this._completionHoldState.count = 0;
604585
605101
  this._completionHoldState.lastKey = "";
@@ -604591,7 +605107,7 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
604591
605107
  this._focusSupervisor?.markCompletionBlocked({
604592
605108
  turn,
604593
605109
  reason: lastCompletionGateReason || "completion requested before required evidence was present",
604594
- requiredNextAction: lastCompletionGateCode === "compile_error_fix_loop" ? "run_verification" : lastCompletionGateCode === "todo_verification" ? "run_verification" : "update_todos"
605110
+ requiredNextAction: lastCompletionGateCode === "delivery_coverage" ? "read_authoritative_target" : lastCompletionGateCode === "compile_error_fix_loop" ? "run_verification" : lastCompletionGateCode === "todo_verification" ? "run_verification" : "update_todos"
604595
605111
  });
604596
605112
  const focusDirective = this._focusSupervisor?.snapshot().directive;
604597
605113
  if (focusDirective) {
@@ -604674,94 +605190,41 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
604674
605190
  };
604675
605191
  let executeSingle = async () => null;
604676
605192
  const turnCap = this.options.maxTurns && this.options.maxTurns > 0 ? this.options.maxTurns : Number.MAX_SAFE_INTEGER;
604677
- const _featureLoopHandled = process.env["OMNIUS_FEATURE_LOOP"] === "1" && !this._inFeatureLoop && !this.options.subAgent;
604678
- if (_featureLoopHandled) {
604679
- try {
604680
- const _survey = await this._resolveFeatureSurvey(task, context2, 0);
604681
- if (!_survey) {
604682
- this.emit({
604683
- type: "status",
604684
- content: "[FEATURE LOOP] deferred: no model-grounded workspace survey was available; continuing with the normal discovery loop",
604685
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604686
- });
604687
- } else {
604688
- const _kind = classifyKind(_survey);
604689
- if (_kind === "investigation") {
604690
- this.emit({
604691
- type: "status",
604692
- content: "[FEATURE LOOP] survey classified this as investigation; continuing with the normal evidence-gathering loop",
604693
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604694
- });
604695
- } else {
604696
- this._inFeatureLoop = true;
604697
- this.emit({
604698
- type: "status",
604699
- content: `[FEATURE LOOP] evidence-grounded survey classified "${_kind}" – entering recursive driver...`,
604700
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604701
- });
604702
- const _root = createRootFeatureNode(task);
604703
- const _startMs = Date.now();
604704
- const _resultNode = await runFeatureNode(_root, {
604705
- rootId: _root.id,
604706
- stateDir: this.omniusStateDir(),
604707
- workingDirectory: this.authoritativeWorkingDirectory() || process.cwd(),
604708
- sessionId: this._sessionId,
604709
- depthCap: 4,
604710
- askApproval: async () => "approve",
604711
- executeUnit: async (unit, node) => {
604712
- const _unitRequest = buildFeatureUnitRequest({
604713
- unit,
604714
- parentRequest: node.request,
604715
- survey: _survey
604716
- });
604717
- const _sub = await this.run(_unitRequest, unit.detail || "Feature unit request is grounded in the parent survey; verify the cited source before mutation.", unit.label);
604718
- return { ok: _sub.status === "completed" };
604719
- },
604720
- runGeneralLoop: async (request) => {
604721
- await this.run(request, void 0, request);
604722
- },
604723
- onPlan: async (artefact) => {
604724
- if (this._longHaul && artefact.lockedContract?.symbols?.length) {
604725
- this._longHaul.seedLockedContract(artefact.lockedContract);
604726
- this.emit({
604727
- type: "status",
604728
- content: `[FEATURE LOOP] seeded ${artefact.lockedContract.symbols.length} locked symbols into WO-6 contract`,
604729
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604730
- });
604731
- }
604732
- }
604733
- }, { survey: _survey });
604734
- this._inFeatureLoop = false;
604735
- const _completed = _resultNode.status === "completed";
604736
- const _durMs = Date.now() - _startMs;
604737
- this.emit({
604738
- type: _completed ? "complete" : "error",
604739
- content: `[FEATURE LOOP] ${_completed ? "completed" : "failed"} after ${_durMs}ms — ${_resultNode.children.length} child nodes`,
604740
- success: _completed,
604741
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604742
- });
604743
- return {
604744
- status: _completed ? "completed" : "incomplete",
604745
- completed: _completed,
604746
- turns: 0,
604747
- toolCalls: 0,
604748
- totalTokens: 0,
604749
- promptTokens: 0,
604750
- completionTokens: 0,
604751
- estimatedTokens: 0,
604752
- summary: `[FEATURE LOOP] ${_completed ? "completed" : "failed"}: ${task.slice(0, 200)}`,
604753
- durationMs: _durMs
604754
- };
604755
- }
604756
- }
604757
- } catch (e2) {
604758
- this._inFeatureLoop = false;
604759
- this.emit({
604760
- type: "status",
604761
- content: `[FEATURE LOOP] error, falling back to general loop: ${e2}`,
604762
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604763
- });
605193
+ const _claimDiscoveryEnabled = (() => {
605194
+ if (typeof this.options.claimDiscovery === "boolean") {
605195
+ return this.options.claimDiscovery;
604764
605196
  }
605197
+ const parse3 = (raw) => {
605198
+ if (raw === void 0)
605199
+ return void 0;
605200
+ const lowered = raw.toLowerCase();
605201
+ if (raw === "1" || lowered === "true" || lowered === "on")
605202
+ return true;
605203
+ if (raw === "0" || lowered === "false" || lowered === "off")
605204
+ return false;
605205
+ return void 0;
605206
+ };
605207
+ const explicit = parse3(process.env["OMNIUS_CLAIM_DISCOVERY"]);
605208
+ if (explicit !== void 0)
605209
+ return explicit;
605210
+ const legacy = parse3(process.env["OMNIUS_FEATURE_LOOP"]);
605211
+ return legacy ?? true;
605212
+ })();
605213
+ const _claimDiscoveryNeedsInit = _claimDiscoveryEnabled && !this._claimDiscoveryInitialized && !this.options.subAgent && this._completionLedger !== null;
605214
+ if (_claimDiscoveryNeedsInit && this._completionLedger) {
605215
+ this._claimDiscoveryInitialized = true;
605216
+ const _survey = await this._resolveClaimDiscoverySurvey(task, 0);
605217
+ this._completionLedger = setClaimDiscoveryState(this._completionLedger, _survey);
605218
+ messages2.push({
605219
+ role: "system",
605220
+ content: "[CLAIM DISCOVERY] Grounding signals (compact):\n" + claimDiscoveryControllerSignals(this._completionLedger.claimDiscovery).join("\n")
605221
+ });
605222
+ this.emit({
605223
+ type: "status",
605224
+ content: `[CLAIM DISCOVERY] initialized from bounded inventory: ${this._completionLedger.claimDiscovery?.candidatePaths.length ?? 0} candidate path(s), status=${this._completionLedger.claimDiscovery?.status ?? "skipped"}`,
605225
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
605226
+ });
605227
+ this._saveCompletionLedgerSafe();
604765
605228
  }
604766
605229
  if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
604767
605230
  const restoredCollapsed = this._textEchoGuard.collapseEchoes(messages2);
@@ -614544,15 +615007,15 @@ ${telegramPersonaHead}` : stripped
614544
615007
  }).slice(0, maxRecoverFiles);
614545
615008
  let recoveredTokens = 0;
614546
615009
  for (const [filePath, entry] of entries) {
614547
- const canonicalPath = this._normalizeEvidencePath(filePath);
614548
- if (alreadyVisiblePaths.has(canonicalPath))
615010
+ const canonicalPath2 = this._normalizeEvidencePath(filePath);
615011
+ if (alreadyVisiblePaths.has(canonicalPath2))
614549
615012
  continue;
614550
615013
  try {
614551
615014
  const { readFileSync: readFileSync147 } = await import("node:fs");
614552
615015
  const absolutePath = this._absoluteToolPath(filePath);
614553
615016
  const content = readFileSync147(absolutePath, "utf8");
614554
615017
  const tokenEst = Math.ceil(content.length / 4);
614555
- const branchNode = this._branchEvidenceByPath.get(canonicalPath);
615018
+ const branchNode = this._branchEvidenceByPath.get(canonicalPath2);
614556
615019
  const currentMtime = this._statMtimeMsForToolPath(filePath) ?? 0;
614557
615020
  const smallCompleteSource = this._mustHonorExplicitFullFileRead(Buffer.byteLength(content, "utf8"), content.split("\n").length, this._branchRoutingContextWindow());
614558
615021
  if (smallCompleteSource) {
@@ -614565,7 +615028,7 @@ ${telegramPersonaHead}` : stripped
614565
615028
  ${content}
614566
615029
  </recovered-file>`
614567
615030
  });
614568
- alreadyVisiblePaths.add(canonicalPath);
615031
+ alreadyVisiblePaths.add(canonicalPath2);
614569
615032
  recoveredFiles.push(filePath);
614570
615033
  recoveredTokens += sourceTokens;
614571
615034
  continue;
@@ -614585,7 +615048,7 @@ ${branchNode.output}
614585
615048
  });
614586
615049
  recoveredFiles.push(filePath);
614587
615050
  recoveredTokens += nodeTokens;
614588
- alreadyVisiblePaths.add(canonicalPath);
615051
+ alreadyVisiblePaths.add(canonicalPath2);
614589
615052
  continue;
614590
615053
  }
614591
615054
  if (branchNode && !branchNode.contractComplete) {
@@ -614594,7 +615057,7 @@ ${branchNode.output}
614594
615057
  if (recoveredTokens + referenceTokens > fileRecoveryBudget)
614595
615058
  continue;
614596
615059
  result.push({ role: "system", content: partialReference });
614597
- alreadyVisiblePaths.add(canonicalPath);
615060
+ alreadyVisiblePaths.add(canonicalPath2);
614598
615061
  recoveredFiles.push(filePath);
614599
615062
  recoveredTokens += referenceTokens;
614600
615063
  continue;
@@ -614613,7 +615076,7 @@ ${branchNode.output}
614613
615076
  const referenceTokens = Math.ceil(reference.length / 4);
614614
615077
  if (recoveredTokens + referenceTokens <= fileRecoveryBudget) {
614615
615078
  result.push({ role: "system", content: reference });
614616
- alreadyVisiblePaths.add(canonicalPath);
615079
+ alreadyVisiblePaths.add(canonicalPath2);
614617
615080
  recoveredFiles.push(filePath);
614618
615081
  recoveredTokens += referenceTokens;
614619
615082
  }
@@ -614977,8 +615440,12 @@ ${trimmedNew}`;
614977
615440
  ...coverage?.gaps.slice(0, 3) ?? []
614978
615441
  ].filter(Boolean).join(" | ") || "none"}`,
614979
615442
  `surviving_blockers=${[...blockedTodos, ...coverage?.gaps.slice(0, 3) ?? []].join(" | ") || "none"}`,
615443
+ `next_claim_inspection=${coverage?.nextInspection?.replace(/\s+/g, " ").slice(0, 420) || "none"}`,
614980
615444
  `evidence_handles=${evidenceHandles.join(",") || "none"}`
614981
615445
  ];
615446
+ if (this._completionLedger?.claimDiscovery) {
615447
+ lines.push(...claimDiscoveryControllerSignals(this._completionLedger.claimDiscovery));
615448
+ }
614982
615449
  const tier = this.options.modelTier ?? "large";
614983
615450
  const directive = this._focusSupervisor?.snapshot().directive;
614984
615451
  if (directive && tier === "small") {
@@ -622375,8 +622842,8 @@ var init_skill_fork = __esm({
622375
622842
  });
622376
622843
 
622377
622844
  // packages/orchestrator/dist/missionArtifacts.js
622378
- import * as fs9 from "node:fs";
622379
- import * as path11 from "node:path";
622845
+ import * as fs7 from "node:fs";
622846
+ import * as path9 from "node:path";
622380
622847
  function createValidationContract(missionId, assertions) {
622381
622848
  return {
622382
622849
  missionId,
@@ -622556,33 +623023,33 @@ function checkMilestoneComplete(state, manifest, milestoneId) {
622556
623023
  return true;
622557
623024
  }
622558
623025
  function writeFeaturesManifest(missionDir, manifest) {
622559
- fs9.mkdirSync(missionDir, { recursive: true });
622560
- const filePath = path11.join(missionDir, "features.json");
622561
- fs9.writeFileSync(filePath, JSON.stringify(manifest, null, 2), "utf-8");
623026
+ fs7.mkdirSync(missionDir, { recursive: true });
623027
+ const filePath = path9.join(missionDir, "features.json");
623028
+ fs7.writeFileSync(filePath, JSON.stringify(manifest, null, 2), "utf-8");
622562
623029
  }
622563
623030
  function writeValidationContract(missionDir, contract) {
622564
- fs9.mkdirSync(missionDir, { recursive: true });
622565
- const filePath = path11.join(missionDir, "validation-contract.md");
622566
- fs9.writeFileSync(filePath, renderValidationContract(contract), "utf-8");
623031
+ fs7.mkdirSync(missionDir, { recursive: true });
623032
+ const filePath = path9.join(missionDir, "validation-contract.md");
623033
+ fs7.writeFileSync(filePath, renderValidationContract(contract), "utf-8");
622567
623034
  }
622568
623035
  function writeValidationState(missionDir, state) {
622569
- fs9.mkdirSync(missionDir, { recursive: true });
622570
- const filePath = path11.join(missionDir, "validation-state.json");
622571
- fs9.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
623036
+ fs7.mkdirSync(missionDir, { recursive: true });
623037
+ const filePath = path9.join(missionDir, "validation-state.json");
623038
+ fs7.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
622572
623039
  }
622573
623040
  function readFeaturesManifest(missionDir) {
622574
- const filePath = path11.join(missionDir, "features.json");
622575
- const content = fs9.readFileSync(filePath, "utf-8");
623041
+ const filePath = path9.join(missionDir, "features.json");
623042
+ const content = fs7.readFileSync(filePath, "utf-8");
622576
623043
  return JSON.parse(content);
622577
623044
  }
622578
623045
  function readValidationState(missionDir) {
622579
- const filePath = path11.join(missionDir, "validation-state.json");
622580
- const content = fs9.readFileSync(filePath, "utf-8");
623046
+ const filePath = path9.join(missionDir, "validation-state.json");
623047
+ const content = fs7.readFileSync(filePath, "utf-8");
622581
623048
  return JSON.parse(content);
622582
623049
  }
622583
623050
  function readValidationContract(missionDir) {
622584
- const filePath = path11.join(missionDir, "validation-contract.md");
622585
- const content = fs9.readFileSync(filePath, "utf-8");
623051
+ const filePath = path9.join(missionDir, "validation-contract.md");
623052
+ const content = fs7.readFileSync(filePath, "utf-8");
622586
623053
  const assertions = [];
622587
623054
  const lines = content.split("\n");
622588
623055
  let inTable = false;
@@ -622920,8 +623387,8 @@ var init_adversarialHandoffs = __esm({
622920
623387
  });
622921
623388
 
622922
623389
  // packages/orchestrator/dist/autoValidators.js
622923
- import * as fs10 from "node:fs";
622924
- import * as path12 from "node:path";
623390
+ import * as fs8 from "node:fs";
623391
+ import * as path10 from "node:path";
622925
623392
  function generateScrutinyValidatorSkill() {
622926
623393
  return `# Scrutiny Validator
622927
623394
 
@@ -623038,22 +623505,22 @@ function combineValidatorResults(missionId, milestoneId, scrutiny, userTesting)
623038
623505
  };
623039
623506
  }
623040
623507
  function writeValidatorResults(missionDir, results) {
623041
- fs10.mkdirSync(missionDir, { recursive: true });
623042
- const filePath = path12.join(missionDir, "validator-results.json");
623043
- fs10.writeFileSync(filePath, JSON.stringify(results, null, 2), "utf-8");
623508
+ fs8.mkdirSync(missionDir, { recursive: true });
623509
+ const filePath = path10.join(missionDir, "validator-results.json");
623510
+ fs8.writeFileSync(filePath, JSON.stringify(results, null, 2), "utf-8");
623044
623511
  }
623045
623512
  function readValidatorResults(missionDir) {
623046
- const filePath = path12.join(missionDir, "validator-results.json");
623047
- const content = fs10.readFileSync(filePath, "utf-8");
623513
+ const filePath = path10.join(missionDir, "validator-results.json");
623514
+ const content = fs8.readFileSync(filePath, "utf-8");
623048
623515
  return JSON.parse(content);
623049
623516
  }
623050
623517
  function writeValidatorSkill(missionDir, skillName, content) {
623051
- const dir = path12.join(missionDir, "skills", "auto-injected");
623052
- if (!fs10.existsSync(dir)) {
623053
- fs10.mkdirSync(dir, { recursive: true });
623518
+ const dir = path10.join(missionDir, "skills", "auto-injected");
623519
+ if (!fs8.existsSync(dir)) {
623520
+ fs8.mkdirSync(dir, { recursive: true });
623054
623521
  }
623055
- const filePath = path12.join(dir, `${skillName}.md`);
623056
- fs10.writeFileSync(filePath, content, "utf-8");
623522
+ const filePath = path10.join(dir, `${skillName}.md`);
623523
+ fs8.writeFileSync(filePath, content, "utf-8");
623057
623524
  }
623058
623525
  var init_autoValidators = __esm({
623059
623526
  "packages/orchestrator/dist/autoValidators.js"() {
@@ -623062,8 +623529,8 @@ var init_autoValidators = __esm({
623062
623529
  });
623063
623530
 
623064
623531
  // packages/orchestrator/dist/serviceManifest.js
623065
- import * as fs11 from "node:fs";
623066
- import * as path13 from "node:path";
623532
+ import * as fs9 from "node:fs";
623533
+ import * as path11 from "node:path";
623067
623534
  function quoteScalar(value2) {
623068
623535
  return JSON.stringify(value2);
623069
623536
  }
@@ -623194,8 +623661,8 @@ function getCommand(manifest, name10) {
623194
623661
  return cmd.command;
623195
623662
  }
623196
623663
  function writeServicesManifest(missionDir, manifest) {
623197
- fs11.mkdirSync(missionDir, { recursive: true });
623198
- const filePath = path13.join(missionDir, "services.yaml");
623664
+ fs9.mkdirSync(missionDir, { recursive: true });
623665
+ const filePath = path11.join(missionDir, "services.yaml");
623199
623666
  const lines = [
623200
623667
  `missionId: ${manifest.missionId}`,
623201
623668
  `createdAt: ${manifest.createdAt}`,
@@ -623243,11 +623710,11 @@ function writeServicesManifest(missionDir, manifest) {
623243
623710
  lines.push(` min: ${manifest.ports.range.min}`);
623244
623711
  lines.push(` max: ${manifest.ports.range.max}`);
623245
623712
  lines.push(` offLimits: [${manifest.ports.offLimits.join(", ")}]`);
623246
- fs11.writeFileSync(filePath, lines.join("\n"), "utf-8");
623713
+ fs9.writeFileSync(filePath, lines.join("\n"), "utf-8");
623247
623714
  }
623248
623715
  function readServicesManifest(missionDir) {
623249
- const filePath = path13.join(missionDir, "services.yaml");
623250
- const content = fs11.readFileSync(filePath, "utf-8");
623716
+ const filePath = path11.join(missionDir, "services.yaml");
623717
+ const content = fs9.readFileSync(filePath, "utf-8");
623251
623718
  const services = [];
623252
623719
  const commands = [];
623253
623720
  let missionId = "";
@@ -624684,6 +625151,549 @@ var init_conversational_scrutiny = __esm({
624684
625151
  }
624685
625152
  });
624686
625153
 
625154
+ // packages/orchestrator/dist/featurePlanner.js
625155
+ import fs10 from "node:fs";
625156
+ import path12 from "node:path";
625157
+ function classifyKind(survey) {
625158
+ const files = survey.files ?? [];
625159
+ const newSym = (survey.newSymbols ?? []).length;
625160
+ const req3 = survey.request.toLowerCase();
625161
+ if (/\b(investigat|why does|how does|trace|understand|root cause|diagnos|explain)\b/.test(req3) && newSym === 0 && files.length <= 2) {
625162
+ return "investigation";
625163
+ }
625164
+ if (/\b(bug|fix|broken|regression|crash|incorrect|fails?|misbehav)/.test(req3) && newSym === 0) {
625165
+ return "bugfix";
625166
+ }
625167
+ if (/\b(refactor|restructure|rename|clean up|simplif|migrate|consolidate)\b/.test(req3) && newSym === 0) {
625168
+ return "refactor";
625169
+ }
625170
+ if (/\b(wir|connect|integrate|hook up|plumb|bridge|glue)\b/.test(req3) && files.length >= 2) {
625171
+ return "wiring";
625172
+ }
625173
+ if (newSym > 0 || /\b(new|create|add|implement|build|introduce|scaffold)\b/.test(req3)) {
625174
+ return "new-module";
625175
+ }
625176
+ return "new-module";
625177
+ }
625178
+ function guessKind(name10) {
625179
+ if (/^(I[A-Z]|.*Interface|.*Contract|.*Spec|.*Event|.*Meta|.*Config|.*State)$/.test(name10)) {
625180
+ return "interface";
625181
+ }
625182
+ if (/^(T|Type|.*Type)$/.test(name10))
625183
+ return "type";
625184
+ if (/^(E|Enum|.*Kind|.*Status|.*Mode)$/.test(name10))
625185
+ return "enum";
625186
+ if (/^[A-Z]/.test(name10))
625187
+ return "class";
625188
+ return "function";
625189
+ }
625190
+ function buildLockedContract(kind, survey) {
625191
+ const symbols = [];
625192
+ if (kind === "refactor") {
625193
+ for (const name10 of survey.existingSymbols ?? []) {
625194
+ symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
625195
+ }
625196
+ } else if (kind === "new-module") {
625197
+ for (const name10 of survey.newSymbols ?? []) {
625198
+ symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
625199
+ }
625200
+ }
625201
+ return { symbols };
625202
+ }
625203
+ function decomposeFeature(survey, kind) {
625204
+ const units = [];
625205
+ const evidenceRefs = claimEvidenceRefs(survey);
625206
+ const unresolvedQuestion = survey.unresolvedQuestions?.[0] ?? (evidenceRefs.length === 0 ? "Which current files, symbols, and tests govern this unit? Inspect them before proposing a mutation." : void 0);
625207
+ const returnContract = "Return the direct result with cited observations, relevant/changed paths, verification or blocker, and the next parent decision.";
625208
+ const withGrounding = (unit) => ({
625209
+ ...unit,
625210
+ evidenceRefs,
625211
+ ...unresolvedQuestion ? { unresolvedQuestion } : {},
625212
+ returnContract
625213
+ });
625214
+ if (kind === "new-module") {
625215
+ const syms = survey.newSymbols ?? [];
625216
+ if (syms.length === 0) {
625217
+ units.push(withGrounding({
625218
+ label: "Establish the module boundary and implement the evidenced unit",
625219
+ size: "large",
625220
+ detail: "Do not scaffold from the request alone. First identify the owning entry point, adjacent contract, and test surface from current evidence."
625221
+ }));
625222
+ } else {
625223
+ for (const name10 of syms) {
625224
+ units.push({
625225
+ ...withGrounding({
625226
+ label: `Implement ${name10} within its evidenced owner`,
625227
+ size: "small",
625228
+ detail: "Confirm the symbol's owning module and contract before editing; do not infer a file path from the request label."
625229
+ }),
625230
+ expectedSymbols: [name10]
625231
+ });
625232
+ }
625233
+ }
625234
+ } else if (kind === "refactor") {
625235
+ units.push(withGrounding({
625236
+ label: "Refactor only the evidenced public surface",
625237
+ size: survey.files.length > 1 ? "large" : "small"
625238
+ }));
625239
+ } else if (kind === "bugfix") {
625240
+ units.push(withGrounding({
625241
+ label: "Reproduce the evidenced failure, make the smallest justified fix, and verify it",
625242
+ size: "small"
625243
+ }));
625244
+ } else if (kind === "wiring") {
625245
+ units.push(withGrounding({
625246
+ label: "Connect the evidenced module boundaries",
625247
+ size: survey.files.length > 2 ? "large" : "small"
625248
+ }));
625249
+ } else {
625250
+ units.push(withGrounding({
625251
+ label: "Investigate the evidence gap and report the next justified action",
625252
+ size: "small"
625253
+ }));
625254
+ }
625255
+ return units;
625256
+ }
625257
+ function claimEvidenceRefs(survey) {
625258
+ const declared = (survey.evidence ?? []).map((item) => item.ref.trim()).filter(Boolean).slice(0, 6);
625259
+ if (declared.length > 0)
625260
+ return declared;
625261
+ return survey.files.map((file) => `survey:file:${file.path}`).filter(Boolean).slice(0, 6);
625262
+ }
625263
+ function buildFeatureUnitRequest(input) {
625264
+ const evidence = (input.survey.evidence ?? []).filter((item) => !input.unit.evidenceRefs?.length || input.unit.evidenceRefs.includes(item.ref)).slice(0, 6);
625265
+ const fallbackEvidence = evidence.length > 0 ? evidence : input.survey.files.slice(0, 6).map((file) => ({
625266
+ ref: `survey:file:${file.path}`,
625267
+ detail: `${file.path}${file.role ? ` — ${file.role}` : ""}`,
625268
+ freshness: "unknown"
625269
+ }));
625270
+ const explicitOpenDeltas = [
625271
+ ...input.unit.unresolvedQuestion ? [input.unit.unresolvedQuestion] : [],
625272
+ ...input.survey.unresolvedQuestions ?? []
625273
+ ].slice(0, 6);
625274
+ const lines = [
625275
+ "[CLAIM UNIT EVIDENCE BRIEF]",
625276
+ `Parent request: ${input.parentRequest.slice(0, 900)}`,
625277
+ `Requested unit: ${input.unit.label}`,
625278
+ `Why now: this unit was selected from the current claim discovery survey, not from a task label alone.`,
625279
+ `Open deltas: ${explicitOpenDeltas.length > 0 ? explicitOpenDeltas.join(" | ") : "none"}`,
625280
+ `Surviving blockers: ${input.unit.unresolvedQuestion ? "blocker carried from planner: open question" : "none"}`,
625281
+ `Evidence handles: ${fallbackEvidence.map((item) => item.ref).join(", ")}`,
625282
+ "Evidence:",
625283
+ ...fallbackEvidence.length > 0 ? fallbackEvidence.map((item) => `- [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail.slice(0, 360)}`) : ["- No current code observation is available; discovery is required before mutation."],
625284
+ `Open question: ${input.unit.unresolvedQuestion ?? "none"}`,
625285
+ "Scope: stay within this unit and directly implicated code; do not broaden the claim without returning to the parent.",
625286
+ `Return contract: ${input.unit.returnContract ?? "Return evidence, verification or blocker, and the next parent decision."}`,
625287
+ "",
625288
+ "Work protocol: inspect the cited files/contracts first. Only mutate after a fresh observation identifies the exact target; if the evidence does not support a target, report the gap instead of fabricating one."
625289
+ ];
625290
+ return lines.filter((line) => Boolean(line)).join("\n");
625291
+ }
625292
+ function renderSpecMarkdown(input) {
625293
+ const { kind, survey, lockedContract, completionContract, decomposition, prose } = input;
625294
+ const lines = [];
625295
+ lines.push(`# Claim Discovery Plan — ${kind}`);
625296
+ lines.push("");
625297
+ lines.push(`**Request:** ${survey.request}`);
625298
+ lines.push("");
625299
+ lines.push(`**Node kind:** \`${kind}\` (selected by CLASSIFY over the survey signals)`);
625300
+ lines.push("");
625301
+ if (prose) {
625302
+ lines.push(`## 1. Intent`);
625303
+ lines.push("");
625304
+ lines.push(prose.trim());
625305
+ lines.push("");
625306
+ }
625307
+ lines.push(`## 2. Survey (codebase as-is)`);
625308
+ lines.push("");
625309
+ if (survey.files.length > 0) {
625310
+ for (const f2 of survey.files) {
625311
+ const refs = f2.lineRefs?.length ? `:${f2.lineRefs.join(",")}` : "";
625312
+ lines.push(`- \`${f2.path}${refs}\`${f2.role ? ` — ${f2.role}` : ""}`);
625313
+ }
625314
+ } else {
625315
+ lines.push("- (no files enumerated in survey)");
625316
+ }
625317
+ if (survey.evidence?.length) {
625318
+ for (const item of survey.evidence.slice(0, 8)) {
625319
+ lines.push(`- evidence [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail}`);
625320
+ }
625321
+ }
625322
+ if (survey.unresolvedQuestions?.length) {
625323
+ lines.push(`- unresolved: ${survey.unresolvedQuestions.join("; ")}`);
625324
+ }
625325
+ lines.push(`- new symbols: ${(survey.newSymbols ?? []).join(", ") || "none"}`);
625326
+ lines.push(`- public surface changes: ${survey.publicSurfaceChanges ? "yes" : "no"}`);
625327
+ lines.push(`- tests exist: ${survey.testsExist ? "yes" : "no"}`);
625328
+ lines.push("");
625329
+ lines.push(`## 3. Locked contract (executable gate)`);
625330
+ lines.push("");
625331
+ if (lockedContract.symbols.length === 0) {
625332
+ lines.push("- (no locked symbols for this kind — disciplined but permissive)");
625333
+ } else {
625334
+ for (const s2 of lockedContract.symbols) {
625335
+ lines.push(`- \`${s2.kind} ${s2.name}\``);
625336
+ }
625337
+ }
625338
+ lines.push("");
625339
+ lines.push(`## 4. Definition of done (CompletionContract)`);
625340
+ lines.push("");
625341
+ lines.push(`- goal: ${completionContract.goalSummary || "(none)"}`);
625342
+ for (const p2 of completionContract.phases ?? []) {
625343
+ lines.push(`- phase: ${p2.label}`);
625344
+ }
625345
+ lines.push("");
625346
+ lines.push(`## 5. Decomposition (SPLIT seed)`);
625347
+ lines.push("");
625348
+ for (const u of decomposition) {
625349
+ lines.push(`- [${u.size}] ${u.label}${u.expectedSymbols?.length ? ` (symbols: ${u.expectedSymbols.join(", ")})` : ""}${u.evidenceRefs?.length ? ` [evidence: ${u.evidenceRefs.join(", ")}]` : ""}`);
625350
+ }
625351
+ lines.push("");
625352
+ lines.push(`## 6. Verification bar`);
625353
+ lines.push("");
625354
+ lines.push("- planner emits real artefacts (this file + locked contract + completion contract)");
625355
+ lines.push("- approval gate blocks before any source edit");
625356
+ lines.push("- WO-6 executor gate activates on locked symbols");
625357
+ lines.push("- recursion + eviction keep context bounded");
625358
+ lines.push("- scope token re-prompts on out-of-scope work");
625359
+ lines.push("");
625360
+ lines.push(`## 7. Handoff notes`);
625361
+ lines.push("");
625362
+ lines.push("- Compose, do not rebuild: this plan reuses spec-gate + completionContract primitives.");
625363
+ lines.push("- Fail-closed: if planning errors, the run falls back to the general agentic loop.");
625364
+ lines.push("");
625365
+ return lines.join("\n");
625366
+ }
625367
+ async function planFeature(survey, options2 = {}) {
625368
+ const kind = classifyKind(survey);
625369
+ const lockedContract = buildLockedContract(kind, survey);
625370
+ const completionContract = inferCompletionContractFromTexts([survey.request, ...survey.rawTexts ?? [], ...survey.signals ?? []], survey.request);
625371
+ const decomposition = decomposeFeature(survey, kind);
625372
+ let prose = "";
625373
+ try {
625374
+ if (options2.proseGenerator) {
625375
+ prose = await options2.proseGenerator({ request: survey.request, kind, survey });
625376
+ }
625377
+ } catch {
625378
+ prose = "";
625379
+ }
625380
+ const specMarkdown = renderSpecMarkdown({
625381
+ kind,
625382
+ survey,
625383
+ lockedContract,
625384
+ completionContract,
625385
+ decomposition,
625386
+ prose
625387
+ });
625388
+ return { kind, specMarkdown, lockedContract, completionContract, decomposition };
625389
+ }
625390
+ function persistPlannerArtefacts(rootId, artefact, stateDir, survey) {
625391
+ try {
625392
+ const dir = path12.join(stateDir, "feature-tree", rootId);
625393
+ fs10.mkdirSync(dir, { recursive: true });
625394
+ fs10.writeFileSync(path12.join(dir, "spec.md"), artefact.specMarkdown, "utf8");
625395
+ fs10.writeFileSync(path12.join(dir, "locked-contract.json"), JSON.stringify(artefact.lockedContract, null, 2), "utf8");
625396
+ fs10.writeFileSync(path12.join(dir, "completion-contract.json"), JSON.stringify(artefact.completionContract, null, 2), "utf8");
625397
+ if (survey) {
625398
+ fs10.writeFileSync(path12.join(dir, "claim-discovery-survey.json"), JSON.stringify({
625399
+ request: survey.request,
625400
+ requestSource: "bound_workspace_inventory",
625401
+ files: survey.files,
625402
+ unresolvedQuestions: survey.unresolvedQuestions ?? [],
625403
+ evidenceRefs: survey.evidence?.map((item) => item.ref) ?? [],
625404
+ signals: survey.signals ?? [],
625405
+ requiredVerificationCommands: survey.requiredVerificationCommands ?? [],
625406
+ testsExist: survey.testsExist ?? false,
625407
+ publicSurfaceChanges: survey.publicSurfaceChanges ?? false,
625408
+ newSymbols: survey.newSymbols ?? [],
625409
+ existingSymbols: survey.existingSymbols ?? []
625410
+ }, null, 2), "utf8");
625411
+ }
625412
+ } catch {
625413
+ }
625414
+ }
625415
+ var classifyClaimKind, buildClaimPlan, buildClaimUnitRequest, buildClaimLockedContract;
625416
+ var init_featurePlanner = __esm({
625417
+ "packages/orchestrator/dist/featurePlanner.js"() {
625418
+ "use strict";
625419
+ init_completionContract();
625420
+ classifyClaimKind = classifyKind;
625421
+ buildClaimPlan = planFeature;
625422
+ buildClaimUnitRequest = buildFeatureUnitRequest;
625423
+ buildClaimLockedContract = buildLockedContract;
625424
+ }
625425
+ });
625426
+
625427
+ // packages/orchestrator/dist/featureApprovalGate.js
625428
+ function mintScopeToken(input) {
625429
+ return {
625430
+ rootId: input.rootId,
625431
+ files: [...input.files ?? []],
625432
+ symbols: input.lockedContract.symbols.map((s2) => s2.name),
625433
+ nodeKinds: input.nodeKinds ?? ["new-module", "refactor", "bugfix", "wiring", "investigation"],
625434
+ depthCap: input.depthCap
625435
+ };
625436
+ }
625437
+ function isWithinScope(input) {
625438
+ const { token } = input;
625439
+ if (typeof input.depth === "number" && input.depth > token.depthCap) {
625440
+ return false;
625441
+ }
625442
+ if (input.nodeKind && !token.nodeKinds.includes(input.nodeKind)) {
625443
+ return false;
625444
+ }
625445
+ if (input.newSymbol && !token.symbols.includes(input.newSymbol)) {
625446
+ return false;
625447
+ }
625448
+ if (input.file) {
625449
+ const file = input.file;
625450
+ const allowed = token.files.some((f2) => {
625451
+ if (f2 === file)
625452
+ return true;
625453
+ if (f2.endsWith("/") && file.startsWith(f2))
625454
+ return true;
625455
+ if (f2.includes("*") && globMatch(f2, file))
625456
+ return true;
625457
+ return false;
625458
+ });
625459
+ if (!allowed)
625460
+ return false;
625461
+ }
625462
+ return true;
625463
+ }
625464
+ function globMatch(pattern, value2) {
625465
+ const re = new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
625466
+ return re.test(value2);
625467
+ }
625468
+ async function requestApproval(req3, ask2, options2 = {}) {
625469
+ let decision2;
625470
+ try {
625471
+ const raw = await ask2(req3);
625472
+ decision2 = raw === "approve" || raw === "edit" || raw === "reject" ? raw : "reject";
625473
+ } catch {
625474
+ decision2 = "reject";
625475
+ }
625476
+ if (decision2 === "approve") {
625477
+ const token = mintScopeToken({
625478
+ rootId: req3.rootId,
625479
+ lockedContract: req3.lockedContract,
625480
+ decomposition: req3.decomposition,
625481
+ depthCap: req3.depthCap,
625482
+ files: options2.files,
625483
+ nodeKinds: options2.nodeKinds
625484
+ });
625485
+ return { decision: decision2, token };
625486
+ }
625487
+ return { decision: decision2 };
625488
+ }
625489
+ var mintClaimScopeToken, isWithinClaimScope, requestClaimApproval;
625490
+ var init_featureApprovalGate = __esm({
625491
+ "packages/orchestrator/dist/featureApprovalGate.js"() {
625492
+ "use strict";
625493
+ mintClaimScopeToken = mintScopeToken;
625494
+ isWithinClaimScope = isWithinScope;
625495
+ requestClaimApproval = requestApproval;
625496
+ }
625497
+ });
625498
+
625499
+ // packages/orchestrator/dist/featureNode.js
625500
+ import fs11 from "node:fs";
625501
+ import path13 from "node:path";
625502
+ function treePath(stateDir, rootId) {
625503
+ return path13.join(stateDir, "feature-tree", `${rootId}.json`);
625504
+ }
625505
+ function saveFeatureTree(stateDir, rootId, nodes) {
625506
+ try {
625507
+ const file = treePath(stateDir, rootId);
625508
+ fs11.mkdirSync(path13.dirname(file), { recursive: true });
625509
+ fs11.writeFileSync(file, JSON.stringify(nodes, null, 2), "utf8");
625510
+ } catch {
625511
+ }
625512
+ }
625513
+ function loadFeatureTree(stateDir, rootId) {
625514
+ try {
625515
+ const file = treePath(stateDir, rootId);
625516
+ if (!fs11.existsSync(file))
625517
+ return null;
625518
+ const raw = JSON.parse(fs11.readFileSync(file, "utf8"));
625519
+ return raw && typeof raw === "object" ? raw : null;
625520
+ } catch {
625521
+ return null;
625522
+ }
625523
+ }
625524
+ function newNodeId(depth, seed) {
625525
+ const h = String(Math.abs(hashString2(seed)) % 1e9).padStart(9, "0");
625526
+ return `fn-d${depth}-${h}`;
625527
+ }
625528
+ function hashString2(s2) {
625529
+ let h = 0;
625530
+ for (let i2 = 0; i2 < s2.length; i2++)
625531
+ h = h * 31 + s2.charCodeAt(i2) | 0;
625532
+ return h;
625533
+ }
625534
+ async function evictNode(node, ctx3, transcript) {
625535
+ try {
625536
+ await runTodoChunker({
625537
+ inputs: {
625538
+ todoId: node.id,
625539
+ todoContent: node.request,
625540
+ turnRange: [0, 0],
625541
+ transcript: transcript || node.request,
625542
+ toolCalls: [],
625543
+ workingDirectory: ctx3.workingDirectory,
625544
+ sessionId: ctx3.sessionId
625545
+ },
625546
+ callable: ctx3.summarizer ?? (async () => "")
625547
+ });
625548
+ } catch {
625549
+ }
625550
+ }
625551
+ async function execUnit(unit, node, ctx3, contract, maxRegenerate) {
625552
+ let result = await ctx3.executeUnit(unit, node);
625553
+ if (!result.ok)
625554
+ return false;
625555
+ const expected = unit.expectedSymbols ?? [];
625556
+ if (expected.length === 0) {
625557
+ return true;
625558
+ }
625559
+ for (let attempt = 0; attempt <= maxRegenerate; attempt++) {
625560
+ if (!result.path || result.source === void 0)
625561
+ return false;
625562
+ const verdict = evaluateExecutorStep({
625563
+ unit: { path: result.path, source: result.source },
625564
+ contract,
625565
+ expectedSymbols: expected
625566
+ });
625567
+ if (verdict.decision === "accept")
625568
+ return true;
625569
+ if (verdict.decision === "replan")
625570
+ return false;
625571
+ result = await ctx3.executeUnit(unit, node);
625572
+ if (!result.ok)
625573
+ return false;
625574
+ }
625575
+ return false;
625576
+ }
625577
+ async function runFeatureNode(node, ctx3, options2, tree2 = {}) {
625578
+ const maxRegenerate = options2.maxRegenerate ?? 2;
625579
+ tree2[node.id] = node;
625580
+ try {
625581
+ const artefact = await planFeature(options2.survey, {
625582
+ proseGenerator: options2.proseGenerator
625583
+ });
625584
+ node.kind = artefact.kind;
625585
+ if (ctx3.onPlan) {
625586
+ try {
625587
+ await ctx3.onPlan(artefact);
625588
+ } catch {
625589
+ }
625590
+ }
625591
+ persistPlannerArtefacts(ctx3.rootId, artefact, ctx3.stateDir, options2.survey);
625592
+ const mustAsk = node.depth === 0 || !node.scopeToken;
625593
+ if (mustAsk && ctx3.askApproval) {
625594
+ node.status = "awaiting_approval";
625595
+ const outcome = await requestApproval({
625596
+ rootId: ctx3.rootId,
625597
+ request: node.request,
625598
+ specMarkdown: artefact.specMarkdown,
625599
+ lockedContract: artefact.lockedContract,
625600
+ decomposition: artefact.decomposition,
625601
+ depthCap: ctx3.depthCap
625602
+ }, ctx3.askApproval, { files: options2.survey.files.map((f2) => f2.path) });
625603
+ if (outcome.decision !== "approve") {
625604
+ node.status = outcome.decision === "edit" ? "planned" : "rejected";
625605
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625606
+ return node;
625607
+ }
625608
+ node.scopeToken = outcome.token;
625609
+ }
625610
+ node.status = "approved";
625611
+ node.status = "executing";
625612
+ let allOk = true;
625613
+ for (const unit of artefact.decomposition) {
625614
+ if (unit.size === "large" && node.depth < ctx3.depthCap) {
625615
+ const childId = newNodeId(node.depth + 1, unit.label + node.id);
625616
+ const childRequest = buildFeatureUnitRequest({
625617
+ unit,
625618
+ parentRequest: node.request,
625619
+ survey: options2.survey
625620
+ });
625621
+ const child = {
625622
+ id: childId,
625623
+ parentId: node.id,
625624
+ depth: node.depth + 1,
625625
+ request: childRequest,
625626
+ kind: artefact.kind,
625627
+ status: "planned",
625628
+ scopeToken: node.scopeToken,
625629
+ children: []
625630
+ };
625631
+ node.children.push(childId);
625632
+ const childSurvey = {
625633
+ ...options2.survey,
625634
+ request: child.request
625635
+ };
625636
+ const childCtx = {
625637
+ ...ctx3,
625638
+ // children inherit the token; re-prompt only if they exceed scope
625639
+ askApproval: (req3) => isWithinScope({
625640
+ token: node.scopeToken,
625641
+ depth: node.depth + 1,
625642
+ nodeKind: artefact.kind
625643
+ }) ? "approve" : ctx3.askApproval(req3)
625644
+ };
625645
+ const res = await runFeatureNode(child, childCtx, { ...options2, survey: childSurvey }, tree2);
625646
+ if (res.status !== "completed")
625647
+ allOk = false;
625648
+ await evictNode(child, ctx3, child.request);
625649
+ } else {
625650
+ const ok3 = await execUnit(unit, node, ctx3, artefact.lockedContract, maxRegenerate);
625651
+ if (!ok3)
625652
+ allOk = false;
625653
+ }
625654
+ }
625655
+ if (allOk) {
625656
+ node.status = "completed";
625657
+ } else {
625658
+ node.status = "failed";
625659
+ }
625660
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625661
+ return node;
625662
+ } catch {
625663
+ if (ctx3.runGeneralLoop) {
625664
+ await ctx3.runGeneralLoop(node.request);
625665
+ node.status = "completed";
625666
+ } else {
625667
+ node.status = "failed";
625668
+ }
625669
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625670
+ return node;
625671
+ }
625672
+ }
625673
+ function createRootFeatureNode(request) {
625674
+ return {
625675
+ id: newNodeId(0, request),
625676
+ parentId: null,
625677
+ depth: 0,
625678
+ request,
625679
+ kind: "new-module",
625680
+ status: "planned",
625681
+ children: []
625682
+ };
625683
+ }
625684
+ var runClaimNode, createClaimRootNode;
625685
+ var init_featureNode = __esm({
625686
+ "packages/orchestrator/dist/featureNode.js"() {
625687
+ "use strict";
625688
+ init_featurePlanner();
625689
+ init_featureApprovalGate();
625690
+ init_spec_gate();
625691
+ init_todo_context_chunker();
625692
+ runClaimNode = runFeatureNode;
625693
+ createClaimRootNode = createRootFeatureNode;
625694
+ }
625695
+ });
625696
+
624687
625697
  // packages/orchestrator/dist/causalAblation.js
624688
625698
  function _identifyAblationTargets(messages2, dimension) {
624689
625699
  const targets = [];
@@ -625209,6 +626219,9 @@ __export(dist_exports3, {
625209
626219
  buildAgentDeploymentPatternSummary: () => buildAgentDeploymentPatternSummary,
625210
626220
  buildAgentNotification: () => buildAgentNotification,
625211
626221
  buildAgentTypeSummary: () => buildAgentTypeSummary,
626222
+ buildClaimLockedContract: () => buildClaimLockedContract,
626223
+ buildClaimPlan: () => buildClaimPlan,
626224
+ buildClaimUnitRequest: () => buildClaimUnitRequest,
625212
626225
  buildCompletionFinalizationRecord: () => buildCompletionFinalizationRecord,
625213
626226
  buildCompletionScenarioDecomposition: () => buildCompletionScenarioDecomposition,
625214
626227
  buildCoordinatorPrompt: () => buildCoordinatorPrompt,
@@ -625235,6 +626248,7 @@ __export(dist_exports3, {
625235
626248
  chooseCheapModelRoute: () => chooseCheapModelRoute,
625236
626249
  claimAssertion: () => claimAssertion,
625237
626250
  classifyBreadth: () => classifyBreadth,
626251
+ classifyClaimKind: () => classifyClaimKind,
625238
626252
  classifyCompletionClaim: () => classifyCompletionClaim,
625239
626253
  classifyHandoff: () => classifyHandoff,
625240
626254
  classifyKind: () => classifyKind,
@@ -625269,6 +626283,7 @@ __export(dist_exports3, {
625269
626283
  countDefinitions: () => countDefinitions,
625270
626284
  createAppState: () => createAppState,
625271
626285
  createChildAbortController: () => createChildAbortController,
626286
+ createClaimRootNode: () => createClaimRootNode,
625272
626287
  createCompletionLedger: () => createCompletionLedger,
625273
626288
  createDefaultContextEngine: () => createDefaultContextEngine,
625274
626289
  createFeaturesManifest: () => createFeaturesManifest,
@@ -625362,6 +626377,7 @@ __export(dist_exports3, {
625362
626377
  isSuccessfulRunFinished: () => isSuccessfulRunFinished,
625363
626378
  isTerminalRunEvent: () => isTerminalRunEvent,
625364
626379
  isTerminalTaskStatus: () => isTerminalTaskStatus,
626380
+ isWithinClaimScope: () => isWithinClaimScope,
625365
626381
  isWithinScope: () => isWithinScope,
625366
626382
  legacyAgenticEventToRunEvent: () => legacyAgenticEventToRunEvent,
625367
626383
  listContextWindowDumps: () => listContextWindowDumps,
@@ -625378,6 +626394,7 @@ __export(dist_exports3, {
625378
626394
  measureContextSNR: () => measureContextSNR,
625379
626395
  memoryCosine: () => cosine4,
625380
626396
  mergeDigests: () => mergeDigests,
626397
+ mintClaimScopeToken: () => mintClaimScopeToken,
625381
626398
  mintScopeToken: () => mintScopeToken,
625382
626399
  normalizeCompletionKey: () => normalizeCompletionKey,
625383
626400
  normalizeMemoryCompilationPlanAudit: () => normalizeMemoryCompilationPlanAudit,
@@ -625396,6 +626413,7 @@ __export(dist_exports3, {
625396
626413
  persistAgentTaskSidecar: () => persistAgentTaskSidecar,
625397
626414
  persistPlannerArtefacts: () => persistPlannerArtefacts,
625398
626415
  planAgentDeploymentPattern: () => planAgentDeploymentPattern,
626416
+ planClaim: () => buildClaimPlan,
625399
626417
  planConsolidation: () => planConsolidation,
625400
626418
  planFeature: () => planFeature,
625401
626419
  prepareCompletionFinalization: () => prepareCompletionFinalization,
@@ -625443,6 +626461,7 @@ __export(dist_exports3, {
625443
626461
  renderValidationContract: () => renderValidationContract,
625444
626462
  renderWorkerSkill: () => renderWorkerSkill,
625445
626463
  requestApproval: () => requestApproval,
626464
+ requestClaimApproval: () => requestClaimApproval,
625446
626465
  resetPluginRegistry: () => resetPluginRegistry,
625447
626466
  resolveAgentTools: () => resolveAgentTools,
625448
626467
  resolveDefaultPoolConfig: () => resolveDefaultPoolConfig,
@@ -625450,6 +626469,7 @@ __export(dist_exports3, {
625450
626469
  resolveModelProfile: () => resolveModelProfile,
625451
626470
  restoreAgentTasks: () => restoreAgentTasks,
625452
626471
  retentionStrength: () => retentionStrength,
626472
+ runClaimNode: () => runClaimNode,
625453
626473
  runFeatureNode: () => runFeatureNode,
625454
626474
  runMemoryCompilerReplay: () => runMemoryCompilerReplay,
625455
626475
  runMemoryCompilerReplaySuite: () => runMemoryCompilerReplaySuite,
@@ -771863,6 +772883,8 @@ async function runCommand2(opts, config) {
771863
772883
  await runBackground(opts.task, mergedConfig, opts);
771864
772884
  } else if (opts.json) {
771865
772885
  await runJson(opts.task, mergedConfig, opts.repoPath);
772886
+ } else if (opts.verbose) {
772887
+ await runConsole(opts.task, mergedConfig, opts.repoPath);
771866
772888
  } else {
771867
772889
  await runWithTUI(opts.task, mergedConfig, opts.repoPath);
771868
772890
  if (shouldForceSingleRunExit()) process.exit(0);
@@ -771962,6 +772984,95 @@ async function runJson(task, config, repoPath2) {
771962
772984
  if (result.exitCode !== 0) process.exit(result.exitCode);
771963
772985
  if (shouldForceJsonExit()) process.exit(0);
771964
772986
  }
772987
+ async function runConsole(task, config, repoPath2) {
772988
+ const startTime = Date.now();
772989
+ const origWrite = process.stdout.write.bind(process.stdout);
772990
+ const origStderr = process.stderr.write.bind(process.stderr);
772991
+ process.stdout.write = (() => true);
772992
+ process.stderr.write = (() => true);
772993
+ let runnerResult = null;
772994
+ let toolCount = 0;
772995
+ const fmtArgs = (args) => {
772996
+ if (args === void 0 || args === null) return "";
772997
+ if (typeof args !== "object") return ` (${String(args)})`;
772998
+ const entries = Object.entries(args);
772999
+ if (entries.length === 0) return "";
773000
+ const parts = entries.map(([k, v]) => {
773001
+ let s2;
773002
+ if (typeof v === "string") {
773003
+ s2 = v.length > 200 ? `${v.slice(0, 197)}…` : v;
773004
+ } else if (v === void 0 || v === null) {
773005
+ s2 = String(v);
773006
+ } else {
773007
+ try {
773008
+ s2 = JSON.stringify(v);
773009
+ } catch {
773010
+ s2 = String(v);
773011
+ }
773012
+ if (s2.length > 200) s2 = `${s2.slice(0, 197)}…`;
773013
+ }
773014
+ return `${k}=${s2}`;
773015
+ });
773016
+ return ` (${parts.join(", ")})`;
773017
+ };
773018
+ const emit2 = (line) => {
773019
+ origWrite(line + "\n");
773020
+ };
773021
+ try {
773022
+ emit2(`▶ Task: ${task}`);
773023
+ await runWithTUI(task, config, repoPath2, {
773024
+ onToolCall: (tool, args) => {
773025
+ toolCount += 1;
773026
+ emit2(`[${toolCount}] 🔧 ${tool}${fmtArgs(args)}`);
773027
+ },
773028
+ onToolResult: (tool, output, success) => {
773029
+ const redacted = getSecretRedactor().redactText(output || "");
773030
+ const capped = redacted && redacted.length > 400 ? redacted.slice(0, 380) + `… [+${redacted.length - 380} chars]` : redacted;
773031
+ const mark = success ? "✓" : "✗";
773032
+ emit2(` ${mark} ${tool} → ${capped || "(no output)"}`);
773033
+ },
773034
+ onStatus: (content) => {
773035
+ if (content && content.trim()) {
773036
+ emit2(`ℹ ${content.trim()}`);
773037
+ }
773038
+ },
773039
+ onAssistantText: (text2) => {
773040
+ const clean6 = sanitizeAgentOutputForUser(text2).trim();
773041
+ if (clean6) emit2(`💬 ${clean6.replace(/\n/g, "\n ")}`);
773042
+ },
773043
+ onRunResult: (result) => {
773044
+ runnerResult = {
773045
+ status: result.status,
773046
+ completed: result.completed,
773047
+ summary: result.summary,
773048
+ turns: result.turns,
773049
+ toolCalls: result.toolCalls
773050
+ };
773051
+ }
773052
+ });
773053
+ } catch (err) {
773054
+ process.stdout.write = origWrite;
773055
+ process.stderr.write = origStderr;
773056
+ emit2(`✗ Error: ${err instanceof Error ? err.message : String(err)}`);
773057
+ if (config.verbose && err instanceof Error && err.stack) {
773058
+ emit2(err.stack);
773059
+ }
773060
+ process.exit(1);
773061
+ }
773062
+ process.stdout.write = origWrite;
773063
+ process.stderr.write = origStderr;
773064
+ const durationMs = Date.now() - startTime;
773065
+ const rr = runnerResult;
773066
+ const status = rr?.completed ? "completed" : rr?.status ?? "completed";
773067
+ emit2("");
773068
+ emit2(
773069
+ `✓ Done — status: ${status} | ${rr?.turns ?? "?"} turns | ${toolCount} tool calls | ${(durationMs / 1e3).toFixed(1)}s`
773070
+ );
773071
+ if (rr?.summary) {
773072
+ emit2(`Summary: ${rr.summary.slice(0, 400)}`);
773073
+ }
773074
+ if (shouldForceSingleRunExit()) process.exit(0);
773075
+ }
771965
773076
  function shouldForceJsonExit() {
771966
773077
  if (process.env["OMNIUS_JSON_NO_FORCE_EXIT"] === "1") return false;
771967
773078
  if (process.env["VITEST"] === "true" || process.env["NODE_ENV"] === "test")
@@ -773253,7 +774364,7 @@ Flags:
773253
774364
  --dry-run Validate patches, don't write to disk
773254
774365
  --offline Use FakeBackend, no backend connection needed
773255
774366
  -l, --local Save settings to .omnius/settings.json (project-local)
773256
- -v, --verbose Verbose output
774367
+ -v, --verbose Lightweight console mode: print each tool call, result, and reasoning step as plain text (no TUI)
773257
774368
  --max-retries <n> Max retries per model request
773258
774369
  --timeout-ms <ms> Overall task timeout
773259
774370
  --suite <name> Eval suite: basic (default) or full