substrate-ai 0.21.9 → 0.21.11
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/acceptance-judge-CKNJdq03.js +4 -0
- package/dist/acceptance-judge-eIZZha1C.js +702 -0
- package/dist/adapter-registry-Z0RlAJY4.js +4 -0
- package/dist/cli/index.js +175 -22
- package/dist/{decision-router-BAPpON_C.js → decision-router-Dyby0fUf.js} +1 -1
- package/dist/{decisions-DMUwdH1O.js → decisions-Cst_r3kF.js} +2 -2
- package/dist/{dist-CO4BbTu3.js → dist-BZGqn-XQ.js} +5 -3
- package/dist/{errors-0OA2nge4.js → errors-xSeGw6pf.js} +2 -2
- package/dist/{experimenter-BTUtFcGu.js → experimenter-hnLiBgcQ.js} +1 -1
- package/dist/health--DIz8sJ9.js +8 -0
- package/dist/{health-BbgLm021.js → health-B867L-8I.js} +3 -3
- package/dist/{index-s7wBSfVT.d.ts → index-Be5MEp2y.d.ts} +2 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.js +2 -2
- package/dist/{interactive-prompt-qTo2iuop.js → interactive-prompt-BvHUcoY4.js} +2 -2
- package/dist/{manifest-read-qsNEHEaF.js → manifest-read-BGzmmY01.js} +268 -5
- package/dist/modules/interactive-prompt/index.js +3 -3
- package/dist/{recovery-engine-BKGBeBnW.js → recovery-engine-dtLHyV4M.js} +2 -2
- package/dist/{routing-Bet3Iu2w.js → routing-BcnHtKAm.js} +2 -2
- package/dist/{run-nda59MmG.js → run-CoZ5kK6c.js} +617 -1169
- package/dist/run-G4HOt6-R.js +15 -0
- package/dist/src/modules/decision-router/index.js +1 -1
- package/dist/src/modules/recovery-engine/index.d.ts +1 -1
- package/dist/src/modules/recovery-engine/index.js +2 -2
- package/dist/{upgrade-Cryksfvg.js → upgrade-BoSsIewI.js} +3 -3
- package/dist/{upgrade-DGpQdA9A.js → upgrade-CNGc12AV.js} +2 -2
- package/dist/version-manager-impl-B9VDdCKb.js +4 -0
- package/dist/{work-graph-repository-DZyJv5pV.js → work-graph-repository-4cKsf8Lf.js} +1 -1
- package/package.json +1 -1
- package/packs/bmad/prompts/acceptance-judge.md +1 -1
- package/dist/adapter-registry-Cr9f2ICC.js +0 -4
- package/dist/health-CLo5vM7O.js +0 -8
- package/dist/run-DXJeZOid.js +0 -14
- package/dist/version-manager-impl-DSK9i3Xk.js +0 -4
- /package/dist/{decisions-CzSIEeGP.js → decisions-BAaxpVD0.js} +0 -0
- /package/dist/{routing-DFxoKHDt.js → routing-DZT5PN3N.js} +0 -0
- /package/dist/{version-manager-impl-qFBiO4Eh.js → version-manager-impl-DMTw551Q.js} +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-B867L-8I.js";
|
|
2
2
|
import { createLogger } from "./logger-KeHncl-f.js";
|
|
3
3
|
import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
|
|
4
|
-
import { ADVISORY_NOTES, BRANCH_PREFIX, CLAUDE_AUTH_FAILURE_HINT, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createGitWorktreeManager, createPipelineRun, createRequirement, detectClaudeAuthFailure, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-
|
|
5
|
-
import { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
4
|
+
import { ADVISORY_NOTES, BRANCH_PREFIX, CLAUDE_AUTH_FAILURE_HINT, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createGitWorktreeManager, createPipelineRun, createRequirement, detectClaudeAuthFailure, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-BZGqn-XQ.js";
|
|
5
|
+
import { ACCEPTANCE_CONTRACT_PROFILE_PATH, FindingsInjector, JOURNEY_DEFERRALS_PATH, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, computeJourneyCoverage, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, effectiveAcceptanceMode, extractTargetFilesFromStoryContent, loadAcceptanceContractFromTrustedTree, loadJourneyDeferralsFromTrustedTree, loadJourneyRegistryFromTrustedTree, parseRuntimeProbes, parseStoryFrontmatter, recordCriticalFail, renderFindings, renderSurface, renderVerdictHtml, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery, summarizeCoverage } from "./manifest-read-BGzmmY01.js";
|
|
6
|
+
import { CodeReviewResultSchema, CreateStoryResultSchema, DevStoryResultSchema, ProbeAuthorResultSchema, TestExpansionResultSchema, TestPlanResultSchema, assemblePrompt, countTokens, getTokenCeiling, runAcceptanceJudge, truncateToTokens } from "./acceptance-judge-eIZZha1C.js";
|
|
7
|
+
import { WorkGraphRepository, detectCycles } from "./work-graph-repository-4cKsf8Lf.js";
|
|
8
|
+
import { deriveExitCode, routeDecision } from "./decision-router-Dyby0fUf.js";
|
|
9
|
+
import { runInteractivePrompt } from "./interactive-prompt-BvHUcoY4.js";
|
|
10
|
+
import { runRecoveryEngine } from "./recovery-engine-dtLHyV4M.js";
|
|
10
11
|
import { basename, dirname, extname, join } from "path";
|
|
11
12
|
import { access, readFile, readdir, stat } from "fs/promises";
|
|
12
13
|
import { EventEmitter } from "node:events";
|
|
@@ -1025,6 +1026,39 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
1025
1026
|
}
|
|
1026
1027
|
]
|
|
1027
1028
|
},
|
|
1029
|
+
{
|
|
1030
|
+
type: "acceptance:canary",
|
|
1031
|
+
description: "Canary self-test (A6.1): reverted a walked-pass journey's wiring commit and re-judged; caught=true means the verdict flipped (gate is honest). A miss auto-demotes the gate to advisory until an operator clears it.",
|
|
1032
|
+
when: "On `substrate acceptance canary` / the optional nightly canary step.",
|
|
1033
|
+
fields: [
|
|
1034
|
+
{
|
|
1035
|
+
name: "ts",
|
|
1036
|
+
type: "string",
|
|
1037
|
+
description: "Timestamp."
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
name: "journey",
|
|
1041
|
+
type: "string",
|
|
1042
|
+
description: "Journey id canaried."
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
name: "caught",
|
|
1046
|
+
type: "boolean",
|
|
1047
|
+
description: "Verdict flipped away from all-PASS."
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
name: "inconclusive",
|
|
1051
|
+
type: "boolean",
|
|
1052
|
+
description: "Canary could not run (revert conflict / render error) — not a miss.",
|
|
1053
|
+
optional: true
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
name: "detail",
|
|
1057
|
+
type: "string",
|
|
1058
|
+
description: "Post-revert verdicts or setup error."
|
|
1059
|
+
}
|
|
1060
|
+
]
|
|
1061
|
+
},
|
|
1028
1062
|
{
|
|
1029
1063
|
type: "acceptance:coverage",
|
|
1030
1064
|
description: "Journey coverage audit result (acceptance gate, A0.3). Every registered journey in scope lands in exactly one state: walked-pass, walked-fail, deferred, unclaimed (NO story claims it — the never-wired-journey class), or unwalked (claimed but never walked). Advisory mode warns; blocking mode escalates the last story of the epic.",
|
|
@@ -2476,7 +2510,7 @@ async function runHelpAgent() {
|
|
|
2476
2510
|
|
|
2477
2511
|
//#endregion
|
|
2478
2512
|
//#region src/persistence/dolt-server.ts
|
|
2479
|
-
const logger$
|
|
2513
|
+
const logger$25 = createLogger("dolt-server");
|
|
2480
2514
|
/**
|
|
2481
2515
|
* Start a dolt sql-server for the given project, if Dolt is available and no
|
|
2482
2516
|
* server is already running (socket already exists).
|
|
@@ -2493,7 +2527,7 @@ async function startDoltServer(projectRoot) {
|
|
|
2493
2527
|
if (!existsSync(join$1(stateDir, ".dolt"))) return null;
|
|
2494
2528
|
try {
|
|
2495
2529
|
await access$1(socketPath);
|
|
2496
|
-
logger$
|
|
2530
|
+
logger$25.debug("Dolt socket already exists at %s — using existing server", socketPath);
|
|
2497
2531
|
return null;
|
|
2498
2532
|
} catch {}
|
|
2499
2533
|
try {
|
|
@@ -2502,10 +2536,10 @@ async function startDoltServer(projectRoot) {
|
|
|
2502
2536
|
stdio: "pipe"
|
|
2503
2537
|
});
|
|
2504
2538
|
} catch {
|
|
2505
|
-
logger$
|
|
2539
|
+
logger$25.debug("dolt binary not on PATH — cannot start server");
|
|
2506
2540
|
return null;
|
|
2507
2541
|
}
|
|
2508
|
-
logger$
|
|
2542
|
+
logger$25.debug("Starting dolt sql-server at %s", socketPath);
|
|
2509
2543
|
let proc$1;
|
|
2510
2544
|
try {
|
|
2511
2545
|
proc$1 = spawn("dolt", [
|
|
@@ -2526,26 +2560,26 @@ async function startDoltServer(projectRoot) {
|
|
|
2526
2560
|
detached: false
|
|
2527
2561
|
});
|
|
2528
2562
|
} catch (err) {
|
|
2529
|
-
logger$
|
|
2563
|
+
logger$25.debug("Failed to spawn dolt sql-server: %s", err instanceof Error ? err.message : String(err));
|
|
2530
2564
|
return null;
|
|
2531
2565
|
}
|
|
2532
2566
|
let failed = false;
|
|
2533
2567
|
proc$1.on("error", (err) => {
|
|
2534
|
-
logger$
|
|
2568
|
+
logger$25.debug("dolt sql-server error: %s", err.message);
|
|
2535
2569
|
failed = true;
|
|
2536
2570
|
});
|
|
2537
2571
|
proc$1.on("exit", (code) => {
|
|
2538
|
-
if (code !== null && code !== 0) logger$
|
|
2572
|
+
if (code !== null && code !== 0) logger$25.debug("dolt sql-server exited with code %d", code);
|
|
2539
2573
|
});
|
|
2540
2574
|
proc$1.stderr?.on("data", (chunk) => {
|
|
2541
2575
|
const line = chunk.toString().trim();
|
|
2542
|
-
if (line) logger$
|
|
2576
|
+
if (line) logger$25.debug("dolt-server: %s", line);
|
|
2543
2577
|
});
|
|
2544
2578
|
const deadline = Date.now() + 5e3;
|
|
2545
2579
|
while (Date.now() < deadline && !failed) try {
|
|
2546
2580
|
await access$1(socketPath);
|
|
2547
2581
|
const pid = proc$1.pid ?? 0;
|
|
2548
|
-
logger$
|
|
2582
|
+
logger$25.info("Auto-started dolt sql-server (pid=%d, socket=%s)", pid, socketPath);
|
|
2549
2583
|
let stopped = false;
|
|
2550
2584
|
return {
|
|
2551
2585
|
pid,
|
|
@@ -2553,14 +2587,14 @@ async function startDoltServer(projectRoot) {
|
|
|
2553
2587
|
stop: () => {
|
|
2554
2588
|
if (stopped) return;
|
|
2555
2589
|
stopped = true;
|
|
2556
|
-
logger$
|
|
2590
|
+
logger$25.debug("Stopping dolt sql-server (pid=%d)", pid);
|
|
2557
2591
|
proc$1.kill("SIGTERM");
|
|
2558
2592
|
}
|
|
2559
2593
|
};
|
|
2560
2594
|
} catch {
|
|
2561
2595
|
await new Promise((resolve$6) => setTimeout(resolve$6, 100));
|
|
2562
2596
|
}
|
|
2563
|
-
logger$
|
|
2597
|
+
logger$25.debug("dolt sql-server did not start within 5s — killing");
|
|
2564
2598
|
proc$1.kill("SIGTERM");
|
|
2565
2599
|
return null;
|
|
2566
2600
|
}
|
|
@@ -2574,63 +2608,9 @@ function registerServerCleanup(handle) {
|
|
|
2574
2608
|
process.on("SIGINT", cleanup);
|
|
2575
2609
|
}
|
|
2576
2610
|
|
|
2577
|
-
//#endregion
|
|
2578
|
-
//#region src/modules/context-compiler/token-counter.ts
|
|
2579
|
-
/**
|
|
2580
|
-
* Token counter utility for the context-compiler module.
|
|
2581
|
-
*
|
|
2582
|
-
* Uses a simple heuristic: chars/4, with a 10% upward adjustment for text
|
|
2583
|
-
* containing fenced code blocks (triple backticks). Intentionally conservative
|
|
2584
|
-
* — better to under-fill a prompt than overflow.
|
|
2585
|
-
*/
|
|
2586
|
-
const CHARS_PER_TOKEN$1 = 4;
|
|
2587
|
-
const CODE_BLOCK_ADJUSTMENT = 1.1;
|
|
2588
|
-
const CODE_BLOCK_MARKER = "```";
|
|
2589
|
-
/**
|
|
2590
|
-
* Approximate the number of tokens in `text`.
|
|
2591
|
-
*
|
|
2592
|
-
* - Base heuristic: `Math.ceil(text.length / 4)`
|
|
2593
|
-
* - If the text contains one or more fenced code blocks (triple backticks),
|
|
2594
|
-
* apply a 10% upward multiplier and re-ceil.
|
|
2595
|
-
*
|
|
2596
|
-
* The approximation is within 15% of actual tokenizer output for typical
|
|
2597
|
-
* prompt content.
|
|
2598
|
-
*/
|
|
2599
|
-
function countTokens(text) {
|
|
2600
|
-
if (text.length === 0) return 0;
|
|
2601
|
-
const base = text.length / CHARS_PER_TOKEN$1;
|
|
2602
|
-
const hasCodeBlock = text.includes(CODE_BLOCK_MARKER);
|
|
2603
|
-
const adjusted = hasCodeBlock ? base * CODE_BLOCK_ADJUSTMENT : base;
|
|
2604
|
-
return Math.ceil(adjusted);
|
|
2605
|
-
}
|
|
2606
|
-
/**
|
|
2607
|
-
* Truncate `text` to approximately `maxTokens` tokens.
|
|
2608
|
-
*
|
|
2609
|
-
* Returns the original text if it already fits within the budget.
|
|
2610
|
-
* Appends a `…` ellipsis suffix when truncation occurs to indicate content
|
|
2611
|
-
* was cut off.
|
|
2612
|
-
*
|
|
2613
|
-
* Note: Because the chars/4 heuristic is an approximation, the truncated
|
|
2614
|
-
* result may still slightly exceed or fall short of the exact token target.
|
|
2615
|
-
*/
|
|
2616
|
-
function truncateToTokens(text, maxTokens) {
|
|
2617
|
-
if (maxTokens <= 0) return "";
|
|
2618
|
-
if (countTokens(text) <= maxTokens) return text;
|
|
2619
|
-
const hasCodeBlock = text.includes(CODE_BLOCK_MARKER);
|
|
2620
|
-
const multiplier = hasCodeBlock ? CODE_BLOCK_ADJUSTMENT : 1;
|
|
2621
|
-
const targetChars = Math.floor(maxTokens * CHARS_PER_TOKEN$1 / multiplier);
|
|
2622
|
-
if (targetChars <= 0) return "";
|
|
2623
|
-
const roughTrunc = text.slice(0, targetChars);
|
|
2624
|
-
const lastSpace = roughTrunc.lastIndexOf(" ", roughTrunc.length - 1);
|
|
2625
|
-
let truncated;
|
|
2626
|
-
if (lastSpace > targetChars - 50 && lastSpace > 0) truncated = roughTrunc.slice(0, lastSpace);
|
|
2627
|
-
else truncated = roughTrunc;
|
|
2628
|
-
return truncated + "…";
|
|
2629
|
-
}
|
|
2630
|
-
|
|
2631
2611
|
//#endregion
|
|
2632
2612
|
//#region src/modules/context-compiler/context-compiler-impl.ts
|
|
2633
|
-
const logger$
|
|
2613
|
+
const logger$24 = createLogger("context-compiler");
|
|
2634
2614
|
/**
|
|
2635
2615
|
* Fraction of the original token budget that must remain (after required +
|
|
2636
2616
|
* important sections) before an optional section is included.
|
|
@@ -2691,7 +2671,7 @@ var ContextCompilerImpl = class {
|
|
|
2691
2671
|
}
|
|
2692
2672
|
_applyExclusionFilter(text, sectionName) {
|
|
2693
2673
|
for (const excludedPath of this._excludedPaths) if (text.includes(excludedPath)) {
|
|
2694
|
-
logger$
|
|
2674
|
+
logger$24.warn({
|
|
2695
2675
|
sectionName,
|
|
2696
2676
|
excludedPath
|
|
2697
2677
|
}, "ContextCompiler: section excluded — contains path from exclusion list");
|
|
@@ -2749,7 +2729,7 @@ var ContextCompilerImpl = class {
|
|
|
2749
2729
|
includedParts.push(truncated);
|
|
2750
2730
|
remainingBudget -= truncatedTokens;
|
|
2751
2731
|
anyTruncated = true;
|
|
2752
|
-
logger$
|
|
2732
|
+
logger$24.warn({
|
|
2753
2733
|
section: section.name,
|
|
2754
2734
|
originalTokens: tokens,
|
|
2755
2735
|
budgetTokens: truncatedTokens
|
|
@@ -2763,7 +2743,7 @@ var ContextCompilerImpl = class {
|
|
|
2763
2743
|
});
|
|
2764
2744
|
} else {
|
|
2765
2745
|
anyTruncated = true;
|
|
2766
|
-
logger$
|
|
2746
|
+
logger$24.warn({
|
|
2767
2747
|
section: section.name,
|
|
2768
2748
|
tokens
|
|
2769
2749
|
}, "Context compiler: omitted \"important\" section — no budget remaining");
|
|
@@ -2790,7 +2770,7 @@ var ContextCompilerImpl = class {
|
|
|
2790
2770
|
} else {
|
|
2791
2771
|
if (tokens > 0) {
|
|
2792
2772
|
anyTruncated = true;
|
|
2793
|
-
logger$
|
|
2773
|
+
logger$24.warn({
|
|
2794
2774
|
section: section.name,
|
|
2795
2775
|
tokens,
|
|
2796
2776
|
budgetFractionRemaining: budgetFractionRemaining.toFixed(2)
|
|
@@ -2884,8 +2864,8 @@ var GrammarLoader = class {
|
|
|
2884
2864
|
_extensionMap;
|
|
2885
2865
|
_cache = new Map();
|
|
2886
2866
|
_unavailable = false;
|
|
2887
|
-
constructor(logger$
|
|
2888
|
-
this._logger = logger$
|
|
2867
|
+
constructor(logger$26) {
|
|
2868
|
+
this._logger = logger$26;
|
|
2889
2869
|
this._extensionMap = new Map([
|
|
2890
2870
|
[".ts", "tree-sitter-typescript/typescript"],
|
|
2891
2871
|
[".tsx", "tree-sitter-typescript/tsx"],
|
|
@@ -2971,9 +2951,9 @@ const ERR_REPO_MAP_GIT_FAILED = "ERR_REPO_MAP_GIT_FAILED";
|
|
|
2971
2951
|
var SymbolParser = class {
|
|
2972
2952
|
_grammarLoader;
|
|
2973
2953
|
_logger;
|
|
2974
|
-
constructor(grammarLoader, logger$
|
|
2954
|
+
constructor(grammarLoader, logger$26) {
|
|
2975
2955
|
this._grammarLoader = grammarLoader;
|
|
2976
|
-
this._logger = logger$
|
|
2956
|
+
this._logger = logger$26;
|
|
2977
2957
|
}
|
|
2978
2958
|
async parseFile(filePath) {
|
|
2979
2959
|
const ext$2 = extname$1(filePath);
|
|
@@ -3118,9 +3098,9 @@ async function computeFileHash(filePath) {
|
|
|
3118
3098
|
var DoltSymbolRepository = class {
|
|
3119
3099
|
_client;
|
|
3120
3100
|
_logger;
|
|
3121
|
-
constructor(client, logger$
|
|
3101
|
+
constructor(client, logger$26) {
|
|
3122
3102
|
this._client = client;
|
|
3123
|
-
this._logger = logger$
|
|
3103
|
+
this._logger = logger$26;
|
|
3124
3104
|
}
|
|
3125
3105
|
/**
|
|
3126
3106
|
* Atomically replace all symbols for filePath.
|
|
@@ -3326,11 +3306,11 @@ var RepoMapStorage = class {
|
|
|
3326
3306
|
_metaRepo;
|
|
3327
3307
|
_gitClient;
|
|
3328
3308
|
_logger;
|
|
3329
|
-
constructor(symbolRepo, metaRepo, gitClient, logger$
|
|
3309
|
+
constructor(symbolRepo, metaRepo, gitClient, logger$26) {
|
|
3330
3310
|
this._symbolRepo = symbolRepo;
|
|
3331
3311
|
this._metaRepo = metaRepo;
|
|
3332
3312
|
this._gitClient = gitClient;
|
|
3333
|
-
this._logger = logger$
|
|
3313
|
+
this._logger = logger$26;
|
|
3334
3314
|
}
|
|
3335
3315
|
/**
|
|
3336
3316
|
* Returns true if the file's current content hash differs from the stored hash.
|
|
@@ -3447,8 +3427,8 @@ function runGit(args, cwd) {
|
|
|
3447
3427
|
*/
|
|
3448
3428
|
var GitClient = class {
|
|
3449
3429
|
_logger;
|
|
3450
|
-
constructor(logger$
|
|
3451
|
-
this._logger = logger$
|
|
3430
|
+
constructor(logger$26) {
|
|
3431
|
+
this._logger = logger$26;
|
|
3452
3432
|
}
|
|
3453
3433
|
/**
|
|
3454
3434
|
* Returns the current HEAD commit SHA.
|
|
@@ -4804,9 +4784,9 @@ var RepoMapQueryEngine = class {
|
|
|
4804
4784
|
repo;
|
|
4805
4785
|
logger;
|
|
4806
4786
|
telemetry;
|
|
4807
|
-
constructor(repo, logger$
|
|
4787
|
+
constructor(repo, logger$26, telemetry) {
|
|
4808
4788
|
this.repo = repo;
|
|
4809
|
-
this.logger = logger$
|
|
4789
|
+
this.logger = logger$26;
|
|
4810
4790
|
this.telemetry = telemetry;
|
|
4811
4791
|
}
|
|
4812
4792
|
async query(q) {
|
|
@@ -5026,9 +5006,9 @@ var RepoMapFormatter = class {
|
|
|
5026
5006
|
var RepoMapTelemetry = class {
|
|
5027
5007
|
_telemetry;
|
|
5028
5008
|
_logger;
|
|
5029
|
-
constructor(telemetry, logger$
|
|
5009
|
+
constructor(telemetry, logger$26) {
|
|
5030
5010
|
this._telemetry = telemetry;
|
|
5031
|
-
this._logger = logger$
|
|
5011
|
+
this._logger = logger$26;
|
|
5032
5012
|
}
|
|
5033
5013
|
/**
|
|
5034
5014
|
* Emit a `repo_map.query` span.
|
|
@@ -5053,9 +5033,9 @@ var RepoMapTelemetry = class {
|
|
|
5053
5033
|
var RepoMapModule = class {
|
|
5054
5034
|
_metaRepo;
|
|
5055
5035
|
_logger;
|
|
5056
|
-
constructor(metaRepo, logger$
|
|
5036
|
+
constructor(metaRepo, logger$26) {
|
|
5057
5037
|
this._metaRepo = metaRepo;
|
|
5058
|
-
this._logger = logger$
|
|
5038
|
+
this._logger = logger$26;
|
|
5059
5039
|
}
|
|
5060
5040
|
/**
|
|
5061
5041
|
* Check whether the stored repo-map is stale relative to the current HEAD commit.
|
|
@@ -5099,9 +5079,9 @@ var RepoMapModule = class {
|
|
|
5099
5079
|
var RepoMapInjector = class {
|
|
5100
5080
|
_queryEngine;
|
|
5101
5081
|
_logger;
|
|
5102
|
-
constructor(queryEngine, logger$
|
|
5082
|
+
constructor(queryEngine, logger$26) {
|
|
5103
5083
|
this._queryEngine = queryEngine;
|
|
5104
|
-
this._logger = logger$
|
|
5084
|
+
this._logger = logger$26;
|
|
5105
5085
|
}
|
|
5106
5086
|
/**
|
|
5107
5087
|
* Build repo-map context by extracting file references from the story content,
|
|
@@ -5183,7 +5163,7 @@ const DEFAULT_TIMEOUTS = {
|
|
|
5183
5163
|
|
|
5184
5164
|
//#endregion
|
|
5185
5165
|
//#region src/modules/agent-dispatch/dispatcher-impl.ts
|
|
5186
|
-
const logger$
|
|
5166
|
+
const logger$23 = createLogger("agent-dispatch");
|
|
5187
5167
|
/**
|
|
5188
5168
|
* Create a new Dispatcher instance.
|
|
5189
5169
|
*
|
|
@@ -5327,7 +5307,7 @@ function runBuildVerification(options) {
|
|
|
5327
5307
|
let cmd;
|
|
5328
5308
|
if (verifyCommand === void 0) {
|
|
5329
5309
|
const detection = detectPackageManager(projectRoot);
|
|
5330
|
-
logger$
|
|
5310
|
+
logger$23.info({
|
|
5331
5311
|
packageManager: detection.packageManager,
|
|
5332
5312
|
lockfile: detection.lockfile,
|
|
5333
5313
|
resolvedCommand: detection.command
|
|
@@ -5339,7 +5319,7 @@ function runBuildVerification(options) {
|
|
|
5339
5319
|
const filters = deriveTurboFilters(changedFiles, projectRoot);
|
|
5340
5320
|
if (filters.length > 0) {
|
|
5341
5321
|
cmd = `${cmd} ${filters.join(" ")}`;
|
|
5342
|
-
logger$
|
|
5322
|
+
logger$23.info({
|
|
5343
5323
|
filters,
|
|
5344
5324
|
originalCmd: options.verifyCommand ?? "(auto-detected)"
|
|
5345
5325
|
}, "Build verification: scoped turbo build to affected packages");
|
|
@@ -5382,7 +5362,7 @@ function runBuildVerification(options) {
|
|
|
5382
5362
|
};
|
|
5383
5363
|
const missingScriptPattern = /Missing script[:\s]|No script found|Command "build" not found/i;
|
|
5384
5364
|
if (missingScriptPattern.test(combinedOutput)) {
|
|
5385
|
-
logger$
|
|
5365
|
+
logger$23.warn("Build script not found — skipping pre-flight (greenfield repo)");
|
|
5386
5366
|
return {
|
|
5387
5367
|
status: "skipped",
|
|
5388
5368
|
exitCode,
|
|
@@ -5392,7 +5372,7 @@ function runBuildVerification(options) {
|
|
|
5392
5372
|
}
|
|
5393
5373
|
const pep668Pattern = /externally-managed-environment|This environment is externally managed/i;
|
|
5394
5374
|
if (pep668Pattern.test(combinedOutput)) {
|
|
5395
|
-
logger$
|
|
5375
|
+
logger$23.warn("PEP 668: pip blocked by externally-managed-environment — skipping pre-flight. Create a .venv to resolve.");
|
|
5396
5376
|
return {
|
|
5397
5377
|
status: "skipped",
|
|
5398
5378
|
exitCode,
|
|
@@ -5402,7 +5382,7 @@ function runBuildVerification(options) {
|
|
|
5402
5382
|
}
|
|
5403
5383
|
const pythonEnvNotProvisionedPattern = /\bpython3?:?\s*command not found|command not found:\s*python3?\b|\bpip3?:?\s*command not found|No module named pip\b/i;
|
|
5404
5384
|
if (pythonEnvNotProvisionedPattern.test(combinedOutput)) {
|
|
5405
|
-
logger$
|
|
5385
|
+
logger$23.warn("Python environment not provisioned (interpreter or pip missing) — skipping build pre-flight. Provide a venv (or a project-profile buildCommand that activates one) to verify Python packages.");
|
|
5406
5386
|
return {
|
|
5407
5387
|
status: "skipped",
|
|
5408
5388
|
exitCode,
|
|
@@ -5625,7 +5605,7 @@ function pickRecommendation(distribution, profile, totalIssues, reviewCycles, la
|
|
|
5625
5605
|
|
|
5626
5606
|
//#endregion
|
|
5627
5607
|
//#region src/modules/implementation-orchestrator/project-findings.ts
|
|
5628
|
-
const logger$
|
|
5608
|
+
const logger$22 = createLogger("project-findings");
|
|
5629
5609
|
/** Maximum character length for the findings summary */
|
|
5630
5610
|
const MAX_CHARS = 2e3;
|
|
5631
5611
|
/**
|
|
@@ -5698,7 +5678,7 @@ async function getProjectFindings(db) {
|
|
|
5698
5678
|
if (summary.length > MAX_CHARS) summary = summary.slice(0, MAX_CHARS - 3) + "...";
|
|
5699
5679
|
return summary;
|
|
5700
5680
|
} catch (err) {
|
|
5701
|
-
logger$
|
|
5681
|
+
logger$22.warn({ err }, "Failed to query project findings (graceful fallback)");
|
|
5702
5682
|
return "";
|
|
5703
5683
|
}
|
|
5704
5684
|
}
|
|
@@ -5719,393 +5699,6 @@ function extractRecurringPatterns(outcomes) {
|
|
|
5719
5699
|
return [...patternCounts.entries()].filter(([, count]) => count >= 2).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => `${pattern} (${count} occurrences)`);
|
|
5720
5700
|
}
|
|
5721
5701
|
|
|
5722
|
-
//#endregion
|
|
5723
|
-
//#region src/modules/compiled-workflows/prompt-assembler.ts
|
|
5724
|
-
const logger$23 = createLogger("compiled-workflows:prompt-assembler");
|
|
5725
|
-
/**
|
|
5726
|
-
* Assemble a final prompt from a template and sections map.
|
|
5727
|
-
*
|
|
5728
|
-
* Steps:
|
|
5729
|
-
* 1. Build a map of placeholder → content from sections array
|
|
5730
|
-
* 2. Replace {{placeholder}} patterns in the template
|
|
5731
|
-
* 3. Estimate total token count
|
|
5732
|
-
* 4. If over ceiling, truncate sections in reverse priority order
|
|
5733
|
-
* 5. Return assembled prompt with token count and truncation flag
|
|
5734
|
-
*
|
|
5735
|
-
* @param template - Prompt template with {{placeholder}} markers
|
|
5736
|
-
* @param sections - Named sections with content and priority
|
|
5737
|
-
* @param tokenCeiling - Hard token ceiling (default: 2200)
|
|
5738
|
-
*/
|
|
5739
|
-
function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
5740
|
-
const contentMap = {};
|
|
5741
|
-
for (const section of sections) contentMap[section.name] = section.content;
|
|
5742
|
-
let prompt = replacePlaceholders(template, contentMap);
|
|
5743
|
-
let tokenCount = countTokens(prompt);
|
|
5744
|
-
if (tokenCount <= tokenCeiling) return {
|
|
5745
|
-
prompt,
|
|
5746
|
-
tokenCount,
|
|
5747
|
-
truncated: false
|
|
5748
|
-
};
|
|
5749
|
-
logger$23.warn({
|
|
5750
|
-
tokenCount,
|
|
5751
|
-
ceiling: tokenCeiling
|
|
5752
|
-
}, "Prompt exceeds token ceiling — truncating optional sections");
|
|
5753
|
-
const priorityOrder = ["optional", "important"];
|
|
5754
|
-
let truncated = false;
|
|
5755
|
-
for (const priority of priorityOrder) {
|
|
5756
|
-
const sectionsAtPriority = sections.filter((s$1) => s$1.priority === priority);
|
|
5757
|
-
for (const section of sectionsAtPriority) {
|
|
5758
|
-
if (tokenCount <= tokenCeiling) break;
|
|
5759
|
-
const overBy = tokenCount - tokenCeiling;
|
|
5760
|
-
const currentSectionTokens = countTokens(section.content);
|
|
5761
|
-
if (currentSectionTokens === 0) continue;
|
|
5762
|
-
const targetSectionTokens = Math.max(0, currentSectionTokens - overBy);
|
|
5763
|
-
if (targetSectionTokens === 0) {
|
|
5764
|
-
contentMap[section.name] = "";
|
|
5765
|
-
logger$23.warn({ sectionName: section.name }, "Section eliminated to fit token budget");
|
|
5766
|
-
} else {
|
|
5767
|
-
contentMap[section.name] = truncateToTokens(section.content, targetSectionTokens);
|
|
5768
|
-
logger$23.warn({
|
|
5769
|
-
sectionName: section.name,
|
|
5770
|
-
targetSectionTokens
|
|
5771
|
-
}, "Section truncated to fit token budget");
|
|
5772
|
-
}
|
|
5773
|
-
truncated = true;
|
|
5774
|
-
prompt = replacePlaceholders(template, contentMap);
|
|
5775
|
-
tokenCount = countTokens(prompt);
|
|
5776
|
-
}
|
|
5777
|
-
if (tokenCount <= tokenCeiling) break;
|
|
5778
|
-
}
|
|
5779
|
-
if (tokenCount > tokenCeiling) logger$23.warn({
|
|
5780
|
-
tokenCount,
|
|
5781
|
-
ceiling: tokenCeiling
|
|
5782
|
-
}, "Required sections alone exceed token ceiling — returning over-budget prompt");
|
|
5783
|
-
return {
|
|
5784
|
-
prompt,
|
|
5785
|
-
tokenCount,
|
|
5786
|
-
truncated
|
|
5787
|
-
};
|
|
5788
|
-
}
|
|
5789
|
-
/**
|
|
5790
|
-
* Replace {{placeholder}} patterns in template with values from contentMap.
|
|
5791
|
-
* Missing placeholders are replaced with an empty string.
|
|
5792
|
-
*/
|
|
5793
|
-
function replacePlaceholders(template, contentMap) {
|
|
5794
|
-
return template.replace(/\{\{(\w[\w_-]*)\}\}/g, (_match, key) => {
|
|
5795
|
-
return contentMap[key] ?? "";
|
|
5796
|
-
});
|
|
5797
|
-
}
|
|
5798
|
-
|
|
5799
|
-
//#endregion
|
|
5800
|
-
//#region src/modules/compiled-workflows/schemas.ts
|
|
5801
|
-
/**
|
|
5802
|
-
* Schema for the YAML output contract of the create-story sub-agent.
|
|
5803
|
-
* The agent must emit YAML matching this shape.
|
|
5804
|
-
*/
|
|
5805
|
-
const CreateStoryResultSchema = z.object({
|
|
5806
|
-
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
5807
|
-
story_file: z.string().optional(),
|
|
5808
|
-
story_key: z.string().optional(),
|
|
5809
|
-
story_title: z.string().optional()
|
|
5810
|
-
});
|
|
5811
|
-
/**
|
|
5812
|
-
* Coerce a YAML value to a plain string. Agents sometimes emit
|
|
5813
|
-
* `ac_failures: [AC7: explanation]` which YAML parses as a mapping
|
|
5814
|
-
* `{ AC7: "explanation" }` instead of a string. This flattens it.
|
|
5815
|
-
*/
|
|
5816
|
-
const coerceToString = z.preprocess((val) => {
|
|
5817
|
-
if (typeof val === "string") return val;
|
|
5818
|
-
if (val !== null && typeof val === "object") return Object.entries(val).map(([k, v]) => `${k}: ${String(v)}`).join(", ");
|
|
5819
|
-
return String(val);
|
|
5820
|
-
}, z.string());
|
|
5821
|
-
/**
|
|
5822
|
-
* Schema for the YAML output contract of the dev-story sub-agent.
|
|
5823
|
-
* The agent must emit YAML matching this shape.
|
|
5824
|
-
*/
|
|
5825
|
-
const DevStoryResultSchema = z.object({
|
|
5826
|
-
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
5827
|
-
ac_met: z.array(coerceToString).default([]),
|
|
5828
|
-
ac_failures: z.array(coerceToString).default([]),
|
|
5829
|
-
files_modified: z.array(z.string()).default([]),
|
|
5830
|
-
tests: z.preprocess((val) => {
|
|
5831
|
-
if (typeof val === "string") {
|
|
5832
|
-
const lower = val.toLowerCase();
|
|
5833
|
-
if (lower.includes("fail")) return "fail";
|
|
5834
|
-
return "pass";
|
|
5835
|
-
}
|
|
5836
|
-
if (val !== null && typeof val === "object") {
|
|
5837
|
-
const obj = val;
|
|
5838
|
-
if (typeof obj.fail === "number" && obj.fail > 0) return "fail";
|
|
5839
|
-
return "pass";
|
|
5840
|
-
}
|
|
5841
|
-
if (typeof val === "number") return val > 0 ? "fail" : "pass";
|
|
5842
|
-
return "pass";
|
|
5843
|
-
}, z.enum(["pass", "fail"])),
|
|
5844
|
-
notes: z.string().optional()
|
|
5845
|
-
});
|
|
5846
|
-
/**
|
|
5847
|
-
* Coerce a YAML value to a number. Agents sometimes emit line numbers
|
|
5848
|
-
* as strings (`"42"` instead of `42`). This handles the conversion.
|
|
5849
|
-
*/
|
|
5850
|
-
const coerceOptionalNumber = z.preprocess((val) => typeof val === "string" ? Number(val) : val, z.number().optional());
|
|
5851
|
-
const coerceNumber = z.preprocess((val) => {
|
|
5852
|
-
if (typeof val === "string") return Number(val);
|
|
5853
|
-
if (Array.isArray(val)) return val.length;
|
|
5854
|
-
return val;
|
|
5855
|
-
}, z.number());
|
|
5856
|
-
/**
|
|
5857
|
-
* Schema for a single issue in the code review output.
|
|
5858
|
-
*/
|
|
5859
|
-
const CodeReviewIssueSchema = z.object({
|
|
5860
|
-
severity: z.enum([
|
|
5861
|
-
"blocker",
|
|
5862
|
-
"major",
|
|
5863
|
-
"minor"
|
|
5864
|
-
]),
|
|
5865
|
-
description: z.string(),
|
|
5866
|
-
file: z.string().optional(),
|
|
5867
|
-
line: coerceOptionalNumber
|
|
5868
|
-
});
|
|
5869
|
-
/**
|
|
5870
|
-
* Schema for a single entry in the AC verification checklist emitted by
|
|
5871
|
-
* the code-review sub-agent. Each entry maps an acceptance criterion to a
|
|
5872
|
-
* status determination backed by concrete evidence from the diff.
|
|
5873
|
-
*/
|
|
5874
|
-
const AcChecklistEntrySchema = z.object({
|
|
5875
|
-
ac_id: z.string().default(""),
|
|
5876
|
-
status: z.enum([
|
|
5877
|
-
"met",
|
|
5878
|
-
"not_met",
|
|
5879
|
-
"partial"
|
|
5880
|
-
]).default("met"),
|
|
5881
|
-
evidence: z.string().default("")
|
|
5882
|
-
});
|
|
5883
|
-
/**
|
|
5884
|
-
* Compute the verdict from the issue list using deterministic rules.
|
|
5885
|
-
*
|
|
5886
|
-
* The agent reports issues with severities; the pipeline computes the
|
|
5887
|
-
* verdict. This decouples model-routing cost decisions (MAJOR_REWORK
|
|
5888
|
-
* triggers opus) from agent judgment, and scales naturally with story
|
|
5889
|
-
* size — severity classification is per-issue, not per-story.
|
|
5890
|
-
*
|
|
5891
|
-
* Rules:
|
|
5892
|
-
* - Any blocker → NEEDS_MAJOR_REWORK (security, data loss, architectural breakage)
|
|
5893
|
-
* - Any major or minor issues → NEEDS_MINOR_FIXES (fixable by sonnet with guidance)
|
|
5894
|
-
* - No issues → SHIP_IT
|
|
5895
|
-
*
|
|
5896
|
-
* Note: LGTM_WITH_NOTES is handled in the transform (not here) because it
|
|
5897
|
-
* requires knowledge of the agent's original verdict.
|
|
5898
|
-
*/
|
|
5899
|
-
function computeVerdict(issueList) {
|
|
5900
|
-
const hasBlocker = issueList.some((i) => i.severity === "blocker");
|
|
5901
|
-
if (hasBlocker) return "NEEDS_MAJOR_REWORK";
|
|
5902
|
-
if (issueList.length > 0) return "NEEDS_MINOR_FIXES";
|
|
5903
|
-
return "SHIP_IT";
|
|
5904
|
-
}
|
|
5905
|
-
/**
|
|
5906
|
-
* Schema for the YAML output contract of the code-review sub-agent.
|
|
5907
|
-
*
|
|
5908
|
-
* The agent must emit YAML with verdict, issues count, issue_list, and
|
|
5909
|
-
* optionally an ac_checklist mapping each AC to its implementation status.
|
|
5910
|
-
* Example:
|
|
5911
|
-
* verdict: NEEDS_MINOR_FIXES
|
|
5912
|
-
* issues: 3
|
|
5913
|
-
* issue_list:
|
|
5914
|
-
* - severity: minor
|
|
5915
|
-
* description: "Missing error handling in createFoo()"
|
|
5916
|
-
* file: "src/modules/foo/foo.ts"
|
|
5917
|
-
* line: 42
|
|
5918
|
-
* ac_checklist:
|
|
5919
|
-
* - ac_id: AC1
|
|
5920
|
-
* status: met
|
|
5921
|
-
* evidence: "Implemented in src/modules/foo/foo.ts:createFoo()"
|
|
5922
|
-
* - ac_id: AC2
|
|
5923
|
-
* status: not_met
|
|
5924
|
-
* evidence: "No implementation found for getConstraints()"
|
|
5925
|
-
* notes: "Generally clean implementation."
|
|
5926
|
-
*
|
|
5927
|
-
* The transform:
|
|
5928
|
-
* 1. Auto-corrects the issues count from issue_list length.
|
|
5929
|
-
* 2. Auto-injects a major issue for each not_met AC not already flagged.
|
|
5930
|
-
* 3. Recomputes the verdict from the (possibly augmented) issue list.
|
|
5931
|
-
* The agent's original verdict is preserved as `agentVerdict` for logging.
|
|
5932
|
-
*/
|
|
5933
|
-
const CodeReviewResultSchema = z.object({
|
|
5934
|
-
verdict: z.enum([
|
|
5935
|
-
"SHIP_IT",
|
|
5936
|
-
"NEEDS_MINOR_FIXES",
|
|
5937
|
-
"NEEDS_MAJOR_REWORK",
|
|
5938
|
-
"LGTM_WITH_NOTES"
|
|
5939
|
-
]),
|
|
5940
|
-
issues: coerceNumber,
|
|
5941
|
-
issue_list: z.array(CodeReviewIssueSchema),
|
|
5942
|
-
ac_checklist: z.array(AcChecklistEntrySchema).default([]),
|
|
5943
|
-
notes: z.string().optional()
|
|
5944
|
-
}).transform((data) => {
|
|
5945
|
-
const augmentedIssueList = [...data.issue_list];
|
|
5946
|
-
for (const entry of data.ac_checklist) if (entry.status === "not_met") {
|
|
5947
|
-
const acIdPattern = new RegExp(`\\b${entry.ac_id}\\b`);
|
|
5948
|
-
const alreadyFlagged = augmentedIssueList.some((issue) => (issue.severity === "major" || issue.severity === "blocker") && acIdPattern.test(issue.description));
|
|
5949
|
-
if (!alreadyFlagged) augmentedIssueList.push({
|
|
5950
|
-
severity: "major",
|
|
5951
|
-
description: `${entry.ac_id} not implemented: ${entry.evidence}`,
|
|
5952
|
-
file: ""
|
|
5953
|
-
});
|
|
5954
|
-
}
|
|
5955
|
-
const computedVerdict = computeVerdict(augmentedIssueList);
|
|
5956
|
-
const finalVerdict = data.verdict === "LGTM_WITH_NOTES" && computedVerdict === "SHIP_IT" ? "LGTM_WITH_NOTES" : computedVerdict;
|
|
5957
|
-
return {
|
|
5958
|
-
...data,
|
|
5959
|
-
issue_list: augmentedIssueList,
|
|
5960
|
-
issues: augmentedIssueList.length,
|
|
5961
|
-
agentVerdict: data.verdict,
|
|
5962
|
-
verdict: finalVerdict
|
|
5963
|
-
};
|
|
5964
|
-
});
|
|
5965
|
-
/**
|
|
5966
|
-
* Schema for the YAML output contract of the test-plan sub-agent.
|
|
5967
|
-
*
|
|
5968
|
-
* The agent must emit YAML with result, test_files, test_categories, and coverage_notes.
|
|
5969
|
-
* Example:
|
|
5970
|
-
* result: success
|
|
5971
|
-
* test_files:
|
|
5972
|
-
* - src/modules/foo/__tests__/foo.test.ts
|
|
5973
|
-
* test_categories:
|
|
5974
|
-
* - unit
|
|
5975
|
-
* - integration
|
|
5976
|
-
* coverage_notes: "AC1 covered by foo.test.ts"
|
|
5977
|
-
*/
|
|
5978
|
-
const TestPlanResultSchema = z.object({
|
|
5979
|
-
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
5980
|
-
test_files: z.array(z.string()).default([]),
|
|
5981
|
-
test_categories: z.array(z.string()).default([]),
|
|
5982
|
-
coverage_notes: z.string().default("")
|
|
5983
|
-
});
|
|
5984
|
-
/**
|
|
5985
|
-
* Schema for a single coverage gap identified during test expansion analysis.
|
|
5986
|
-
*/
|
|
5987
|
-
const CoverageGapSchema = z.object({
|
|
5988
|
-
ac_ref: z.string(),
|
|
5989
|
-
description: z.string(),
|
|
5990
|
-
gap_type: z.enum([
|
|
5991
|
-
"missing-e2e",
|
|
5992
|
-
"missing-integration",
|
|
5993
|
-
"unit-only"
|
|
5994
|
-
])
|
|
5995
|
-
});
|
|
5996
|
-
/**
|
|
5997
|
-
* Schema for a single suggested test generated during test expansion analysis.
|
|
5998
|
-
*/
|
|
5999
|
-
const SuggestedTestSchema = z.object({
|
|
6000
|
-
test_name: z.string(),
|
|
6001
|
-
test_type: z.enum([
|
|
6002
|
-
"e2e",
|
|
6003
|
-
"integration",
|
|
6004
|
-
"unit"
|
|
6005
|
-
]),
|
|
6006
|
-
description: z.string(),
|
|
6007
|
-
target_ac: z.string().optional()
|
|
6008
|
-
});
|
|
6009
|
-
/**
|
|
6010
|
-
* Schema for the YAML output contract of the test-expansion sub-agent.
|
|
6011
|
-
*
|
|
6012
|
-
* The agent must emit YAML with expansion_priority, coverage_gaps, and suggested_tests.
|
|
6013
|
-
* Example:
|
|
6014
|
-
* expansion_priority: medium
|
|
6015
|
-
* coverage_gaps:
|
|
6016
|
-
* - ac_ref: AC1
|
|
6017
|
-
* description: "Happy path not exercised at module boundary"
|
|
6018
|
-
* gap_type: missing-integration
|
|
6019
|
-
* suggested_tests:
|
|
6020
|
-
* - test_name: "runFoo integration happy path"
|
|
6021
|
-
* test_type: integration
|
|
6022
|
-
* description: "Test runFoo with real DB to verify AC1 end-to-end"
|
|
6023
|
-
* target_ac: AC1
|
|
6024
|
-
* notes: "Unit coverage is solid but integration layer is untested."
|
|
6025
|
-
*/
|
|
6026
|
-
const TestExpansionResultSchema = z.object({
|
|
6027
|
-
expansion_priority: z.preprocess((val) => [
|
|
6028
|
-
"low",
|
|
6029
|
-
"medium",
|
|
6030
|
-
"high"
|
|
6031
|
-
].includes(val) ? val : "low", z.enum([
|
|
6032
|
-
"low",
|
|
6033
|
-
"medium",
|
|
6034
|
-
"high"
|
|
6035
|
-
])),
|
|
6036
|
-
coverage_gaps: z.array(CoverageGapSchema).default([]),
|
|
6037
|
-
suggested_tests: z.array(SuggestedTestSchema).default([]),
|
|
6038
|
-
notes: z.string().optional()
|
|
6039
|
-
});
|
|
6040
|
-
/**
|
|
6041
|
-
* Inline mirror of RuntimeProbeSchema from @substrate-ai/sdlc.
|
|
6042
|
-
*
|
|
6043
|
-
* Inlined here instead of imported to avoid triggering Vitest's mock validation
|
|
6044
|
-
* error in orchestrator tests that mock @substrate-ai/sdlc without including
|
|
6045
|
-
* RuntimeProbeListSchema. The canonical definition lives in
|
|
6046
|
-
* packages/sdlc/src/verification/probes/types.ts — keep in sync when that
|
|
6047
|
-
* schema changes.
|
|
6048
|
-
*/
|
|
6049
|
-
const InlineRuntimeProbeSchema = z.object({
|
|
6050
|
-
name: z.string().min(1, "probe name is required"),
|
|
6051
|
-
sandbox: z.enum(["host", "twin"]),
|
|
6052
|
-
command: z.string().min(1, "probe command is required"),
|
|
6053
|
-
timeout_ms: z.number().int().positive().optional(),
|
|
6054
|
-
description: z.string().optional(),
|
|
6055
|
-
expect_stdout_no_regex: z.array(z.string().min(1)).optional(),
|
|
6056
|
-
expect_stdout_regex: z.array(z.string().min(1)).optional()
|
|
6057
|
-
});
|
|
6058
|
-
const InlineRuntimeProbeListSchema = z.array(InlineRuntimeProbeSchema);
|
|
6059
|
-
/**
|
|
6060
|
-
* Schema for the YAML output contract of the probe-author sub-agent.
|
|
6061
|
-
*
|
|
6062
|
-
* The agent emits a yaml block containing result and probes list.
|
|
6063
|
-
* The probes field is validated against the RuntimeProbe shape from @substrate-ai/sdlc
|
|
6064
|
-
* (inlined to avoid module mock conflicts in orchestrator unit tests).
|
|
6065
|
-
*
|
|
6066
|
-
* Example:
|
|
6067
|
-
* result: success
|
|
6068
|
-
* probes:
|
|
6069
|
-
* - name: my-probe
|
|
6070
|
-
* sandbox: host
|
|
6071
|
-
* command: echo "hello"
|
|
6072
|
-
*/
|
|
6073
|
-
const ProbeAuthorResultSchema = z.object({
|
|
6074
|
-
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
6075
|
-
probes: InlineRuntimeProbeListSchema
|
|
6076
|
-
});
|
|
6077
|
-
/**
|
|
6078
|
-
* Per-end-state verdict from the acceptance judge.
|
|
6079
|
-
*
|
|
6080
|
-
* UNREACHABLE is first-class and distinct from FAIL: the walk could not even
|
|
6081
|
-
* be attempted because the affordance does not exist in the rendered surface
|
|
6082
|
-
* — it is what the income-sources UJ-2 failure WAS. Evidence is MANDATORY:
|
|
6083
|
-
* a verdict that cannot cite the artifact region it grounds on is
|
|
6084
|
-
* schema-invalid (naive prose judging is banned by construction — the
|
|
6085
|
-
* documented LLM-judge biases make ungrounded verdicts worthless).
|
|
6086
|
-
*/
|
|
6087
|
-
const AcceptanceJudgeVerdictSchema = z.object({
|
|
6088
|
-
end_state_id: z.string().min(1),
|
|
6089
|
-
verdict: z.preprocess((val) => typeof val === "string" ? val.toUpperCase() : val, z.enum([
|
|
6090
|
-
"PASS",
|
|
6091
|
-
"FAIL",
|
|
6092
|
-
"UNREACHABLE"
|
|
6093
|
-
])),
|
|
6094
|
-
evidence: z.object({
|
|
6095
|
-
artifact: z.string().min(1),
|
|
6096
|
-
excerpt: z.string().min(1)
|
|
6097
|
-
}),
|
|
6098
|
-
reasoning: z.string().optional()
|
|
6099
|
-
});
|
|
6100
|
-
/**
|
|
6101
|
-
* Schema for the YAML output contract of the acceptance-judge sub-agent.
|
|
6102
|
-
*/
|
|
6103
|
-
const AcceptanceJudgeResultSchema = z.object({
|
|
6104
|
-
result: z.preprocess((val) => val === "failure" ? "failed" : val, z.enum(["success", "failed"])),
|
|
6105
|
-
verdicts: z.array(AcceptanceJudgeVerdictSchema).default([]),
|
|
6106
|
-
error: z.string().optional()
|
|
6107
|
-
});
|
|
6108
|
-
|
|
6109
5702
|
//#endregion
|
|
6110
5703
|
//#region src/modules/implementation-orchestrator/epic-paths.ts
|
|
6111
5704
|
/** Default planning directories scanned for per-epic/glob files, priority order. */
|
|
@@ -6164,49 +5757,9 @@ function resolveEpicsPathOverride(projectRoot) {
|
|
|
6164
5757
|
}
|
|
6165
5758
|
}
|
|
6166
5759
|
|
|
6167
|
-
//#endregion
|
|
6168
|
-
//#region src/modules/compiled-workflows/token-ceiling.ts
|
|
6169
|
-
/**
|
|
6170
|
-
* Default token ceilings for each compiled workflow.
|
|
6171
|
-
* These match the hardcoded constants previously defined inline in each workflow.
|
|
6172
|
-
*/
|
|
6173
|
-
const TOKEN_CEILING_DEFAULTS = {
|
|
6174
|
-
"create-story": 5e4,
|
|
6175
|
-
"dev-story": 4e5,
|
|
6176
|
-
"code-review": 5e5,
|
|
6177
|
-
"test-plan": 1e5,
|
|
6178
|
-
"test-expansion": 2e5,
|
|
6179
|
-
"probe-author": 5e4,
|
|
6180
|
-
"acceptance-judge": 1e5
|
|
6181
|
-
};
|
|
6182
|
-
/**
|
|
6183
|
-
* Resolve the effective token ceiling for a workflow type.
|
|
6184
|
-
*
|
|
6185
|
-
* Returns the ceiling from `tokenCeilings` config if present and valid,
|
|
6186
|
-
* otherwise falls back to the hardcoded default.
|
|
6187
|
-
*
|
|
6188
|
-
* @param workflowType - One of: 'create-story', 'dev-story', 'code-review', 'test-plan', 'test-expansion'
|
|
6189
|
-
* @param tokenCeilings - Optional per-workflow overrides from parsed config
|
|
6190
|
-
* @returns `{ ceiling: number, source: 'config' | 'default' }`
|
|
6191
|
-
*/
|
|
6192
|
-
function getTokenCeiling(workflowType, tokenCeilings) {
|
|
6193
|
-
if (tokenCeilings !== void 0) {
|
|
6194
|
-
const configured = tokenCeilings[workflowType];
|
|
6195
|
-
if (configured !== void 0) return {
|
|
6196
|
-
ceiling: configured,
|
|
6197
|
-
source: "config"
|
|
6198
|
-
};
|
|
6199
|
-
}
|
|
6200
|
-
const defaultValue = TOKEN_CEILING_DEFAULTS[workflowType] ?? 0;
|
|
6201
|
-
return {
|
|
6202
|
-
ceiling: defaultValue,
|
|
6203
|
-
source: "default"
|
|
6204
|
-
};
|
|
6205
|
-
}
|
|
6206
|
-
|
|
6207
5760
|
//#endregion
|
|
6208
5761
|
//#region src/modules/compiled-workflows/create-story.ts
|
|
6209
|
-
const logger$
|
|
5762
|
+
const logger$21 = createLogger("compiled-workflows:create-story");
|
|
6210
5763
|
/**
|
|
6211
5764
|
* Compute a hex SHA-256 of the normalized source AC section text.
|
|
6212
5765
|
*
|
|
@@ -6241,13 +5794,13 @@ function hashSourceAcSection(section) {
|
|
|
6241
5794
|
*/
|
|
6242
5795
|
async function runCreateStory(deps, params) {
|
|
6243
5796
|
const { epicId, storyKey, pipelineRunId, source_ac_hash, priorDriftFeedback } = params;
|
|
6244
|
-
logger$
|
|
5797
|
+
logger$21.debug({
|
|
6245
5798
|
epicId,
|
|
6246
5799
|
storyKey,
|
|
6247
5800
|
pipelineRunId
|
|
6248
5801
|
}, "Starting create-story workflow");
|
|
6249
5802
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("create-story", deps.tokenCeilings);
|
|
6250
|
-
logger$
|
|
5803
|
+
logger$21.info({
|
|
6251
5804
|
workflow: "create-story",
|
|
6252
5805
|
ceiling: TOKEN_CEILING,
|
|
6253
5806
|
source: tokenCeilingSource
|
|
@@ -6257,7 +5810,7 @@ async function runCreateStory(deps, params) {
|
|
|
6257
5810
|
template = await deps.pack.getPrompt("create-story");
|
|
6258
5811
|
} catch (err) {
|
|
6259
5812
|
const error = err instanceof Error ? err.message : String(err);
|
|
6260
|
-
logger$
|
|
5813
|
+
logger$21.error({ error }, "Failed to retrieve create-story prompt template");
|
|
6261
5814
|
return {
|
|
6262
5815
|
result: "failed",
|
|
6263
5816
|
error: `Failed to retrieve prompt template: ${error}`,
|
|
@@ -6274,7 +5827,7 @@ async function runCreateStory(deps, params) {
|
|
|
6274
5827
|
const storySection = extractStorySection(epicShardContent, storyKey);
|
|
6275
5828
|
if (storySection !== null) {
|
|
6276
5829
|
const computedHash = hashSourceAcSection(storySection);
|
|
6277
|
-
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$
|
|
5830
|
+
if (source_ac_hash !== void 0 && source_ac_hash !== computedHash) logger$21.debug({
|
|
6278
5831
|
storyKey,
|
|
6279
5832
|
suppliedHash: source_ac_hash,
|
|
6280
5833
|
computedHash
|
|
@@ -6289,7 +5842,7 @@ async function runCreateStory(deps, params) {
|
|
|
6289
5842
|
const storyDef = storyDecisions.find((d) => d.category === "stories" && d.key === storyKey);
|
|
6290
5843
|
if (storyDef) {
|
|
6291
5844
|
storyDefinitionContent = storyDef.value;
|
|
6292
|
-
logger$
|
|
5845
|
+
logger$21.debug({ storyKey }, "Injected story definition from solutioning decisions");
|
|
6293
5846
|
}
|
|
6294
5847
|
} catch {}
|
|
6295
5848
|
const archConstraintsContent = await getArchConstraints$3(deps);
|
|
@@ -6299,11 +5852,11 @@ async function runCreateStory(deps, params) {
|
|
|
6299
5852
|
if (trustedRoot !== void 0) {
|
|
6300
5853
|
const registryLoad = await loadJourneyRegistryFromTrustedTree(trustedRoot);
|
|
6301
5854
|
if (registryLoad.status === "ok" && registryLoad.registry.journeys.length > 0) journeyRegistry = registryLoad.registry;
|
|
6302
|
-
else if (registryLoad.status === "invalid") logger$
|
|
5855
|
+
else if (registryLoad.status === "invalid") logger$21.warn({
|
|
6303
5856
|
storyKey,
|
|
6304
5857
|
issues: registryLoad.issues
|
|
6305
5858
|
}, "A0.2: journey registry present but invalid — stories will be untagged (registry validity is escalated at epic close)");
|
|
6306
|
-
else if (registryLoad.status === "error") logger$
|
|
5859
|
+
else if (registryLoad.status === "error") logger$21.warn({
|
|
6307
5860
|
storyKey,
|
|
6308
5861
|
error: registryLoad.message
|
|
6309
5862
|
}, "A0.2: journey registry read failed — stories will be untagged");
|
|
@@ -6364,7 +5917,7 @@ async function runCreateStory(deps, params) {
|
|
|
6364
5917
|
priority: "optional"
|
|
6365
5918
|
}]
|
|
6366
5919
|
], TOKEN_CEILING);
|
|
6367
|
-
logger$
|
|
5920
|
+
logger$21.debug({
|
|
6368
5921
|
tokenCount,
|
|
6369
5922
|
truncated,
|
|
6370
5923
|
tokenCeiling: TOKEN_CEILING
|
|
@@ -6384,7 +5937,7 @@ async function runCreateStory(deps, params) {
|
|
|
6384
5937
|
dispatchResult = await handle.result;
|
|
6385
5938
|
} catch (err) {
|
|
6386
5939
|
const error = err instanceof Error ? err.message : String(err);
|
|
6387
|
-
logger$
|
|
5940
|
+
logger$21.error({
|
|
6388
5941
|
epicId,
|
|
6389
5942
|
storyKey,
|
|
6390
5943
|
error
|
|
@@ -6405,7 +5958,7 @@ async function runCreateStory(deps, params) {
|
|
|
6405
5958
|
if (dispatchResult.status === "failed") {
|
|
6406
5959
|
const errorMsg = dispatchResult.parseError ?? `Dispatch failed with exit code ${dispatchResult.exitCode}`;
|
|
6407
5960
|
const stderrDetail = dispatchResult.output ? ` Output: ${dispatchResult.output}` : "";
|
|
6408
|
-
logger$
|
|
5961
|
+
logger$21.warn({
|
|
6409
5962
|
epicId,
|
|
6410
5963
|
storyKey,
|
|
6411
5964
|
exitCode: dispatchResult.exitCode,
|
|
@@ -6418,7 +5971,7 @@ async function runCreateStory(deps, params) {
|
|
|
6418
5971
|
};
|
|
6419
5972
|
}
|
|
6420
5973
|
if (dispatchResult.status === "timeout") {
|
|
6421
|
-
logger$
|
|
5974
|
+
logger$21.warn({
|
|
6422
5975
|
epicId,
|
|
6423
5976
|
storyKey
|
|
6424
5977
|
}, "Create-story dispatch timed out");
|
|
@@ -6433,7 +5986,7 @@ async function runCreateStory(deps, params) {
|
|
|
6433
5986
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
6434
5987
|
const authSignature = detectClaudeAuthFailure(dispatchResult.output);
|
|
6435
5988
|
if (authSignature !== null) {
|
|
6436
|
-
logger$
|
|
5989
|
+
logger$21.error({
|
|
6437
5990
|
epicId,
|
|
6438
5991
|
storyKey,
|
|
6439
5992
|
authSignature,
|
|
@@ -6446,7 +5999,7 @@ async function runCreateStory(deps, params) {
|
|
|
6446
5999
|
tokenUsage
|
|
6447
6000
|
};
|
|
6448
6001
|
}
|
|
6449
|
-
logger$
|
|
6002
|
+
logger$21.warn({
|
|
6450
6003
|
epicId,
|
|
6451
6004
|
storyKey,
|
|
6452
6005
|
details,
|
|
@@ -6462,7 +6015,7 @@ async function runCreateStory(deps, params) {
|
|
|
6462
6015
|
const parseResult = CreateStoryResultSchema.safeParse(dispatchResult.parsed);
|
|
6463
6016
|
if (!parseResult.success) {
|
|
6464
6017
|
const details = parseResult.error.message;
|
|
6465
|
-
logger$
|
|
6018
|
+
logger$21.warn({
|
|
6466
6019
|
epicId,
|
|
6467
6020
|
storyKey,
|
|
6468
6021
|
details
|
|
@@ -6489,7 +6042,7 @@ async function runCreateStory(deps, params) {
|
|
|
6489
6042
|
const unknown = taggedJourneys.filter((id) => !knownIds.has(id));
|
|
6490
6043
|
if (unknown.length > 0) {
|
|
6491
6044
|
const details = `story artifact declares unknown journey id(s): ${unknown.join(", ")} — registry v${String(journeyRegistry.version)} defines: ${[...knownIds].join(", ")}`;
|
|
6492
|
-
logger$
|
|
6045
|
+
logger$21.warn({
|
|
6493
6046
|
epicId,
|
|
6494
6047
|
storyKey,
|
|
6495
6048
|
unknown
|
|
@@ -6502,7 +6055,7 @@ async function runCreateStory(deps, params) {
|
|
|
6502
6055
|
};
|
|
6503
6056
|
}
|
|
6504
6057
|
if (taggedJourneys.length > 0) {
|
|
6505
|
-
logger$
|
|
6058
|
+
logger$21.info({
|
|
6506
6059
|
epicId,
|
|
6507
6060
|
storyKey,
|
|
6508
6061
|
journeys: taggedJourneys
|
|
@@ -6511,7 +6064,7 @@ async function runCreateStory(deps, params) {
|
|
|
6511
6064
|
}
|
|
6512
6065
|
}
|
|
6513
6066
|
}
|
|
6514
|
-
logger$
|
|
6067
|
+
logger$21.info({
|
|
6515
6068
|
epicId,
|
|
6516
6069
|
storyKey,
|
|
6517
6070
|
storyFile: parsed.story_file,
|
|
@@ -6541,7 +6094,7 @@ async function getImplementationDecisions(deps, pipelineRunId) {
|
|
|
6541
6094
|
}
|
|
6542
6095
|
return await getDecisionsByPhase(deps.db, "implementation");
|
|
6543
6096
|
} catch (err) {
|
|
6544
|
-
logger$
|
|
6097
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve implementation decisions");
|
|
6545
6098
|
return [];
|
|
6546
6099
|
}
|
|
6547
6100
|
}
|
|
@@ -6839,7 +6392,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6839
6392
|
if (storyKey) {
|
|
6840
6393
|
const perStoryShard = decisions.find((d) => d.category === "epic-shard" && d.key === storyKey);
|
|
6841
6394
|
if (perStoryShard?.value) {
|
|
6842
|
-
logger$
|
|
6395
|
+
logger$21.debug({
|
|
6843
6396
|
epicId,
|
|
6844
6397
|
storyKey
|
|
6845
6398
|
}, "Found per-story epic shard (direct lookup)");
|
|
@@ -6851,13 +6404,13 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6851
6404
|
if (shardContent && storyKey) {
|
|
6852
6405
|
const storySection = extractStorySection(shardContent, storyKey);
|
|
6853
6406
|
if (storySection) {
|
|
6854
|
-
logger$
|
|
6407
|
+
logger$21.debug({
|
|
6855
6408
|
epicId,
|
|
6856
6409
|
storyKey
|
|
6857
6410
|
}, "Extracted per-story section from epic shard (pre-37-0 fallback)");
|
|
6858
6411
|
return storySection;
|
|
6859
6412
|
}
|
|
6860
|
-
logger$
|
|
6413
|
+
logger$21.info({
|
|
6861
6414
|
epicId,
|
|
6862
6415
|
storyKey
|
|
6863
6416
|
}, "Story section absent in decisions-store shard — attempting file-based fallback before returning stale shard");
|
|
@@ -6865,11 +6418,11 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6865
6418
|
if (projectRoot) {
|
|
6866
6419
|
const fallback = readEpicShardFromFile(projectRoot, epicId, storyKey);
|
|
6867
6420
|
if (fallback) {
|
|
6868
|
-
logger$
|
|
6421
|
+
logger$21.info({ epicId }, "Using file-based fallback for epic shard");
|
|
6869
6422
|
if (storyKey) {
|
|
6870
6423
|
const storySection = extractStorySection(fallback, storyKey);
|
|
6871
6424
|
if (storySection) {
|
|
6872
|
-
logger$
|
|
6425
|
+
logger$21.debug({
|
|
6873
6426
|
epicId,
|
|
6874
6427
|
storyKey
|
|
6875
6428
|
}, "Extracted per-story section from file-based epic shard");
|
|
@@ -6882,7 +6435,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
6882
6435
|
if (shardContent) return shardContent;
|
|
6883
6436
|
return "";
|
|
6884
6437
|
} catch (err) {
|
|
6885
|
-
logger$
|
|
6438
|
+
logger$21.warn({
|
|
6886
6439
|
epicId,
|
|
6887
6440
|
error: err instanceof Error ? err.message : String(err)
|
|
6888
6441
|
}, "Failed to retrieve epic shard");
|
|
@@ -6899,7 +6452,7 @@ function getPrevDevNotes(decisions, epicId) {
|
|
|
6899
6452
|
if (devNotes.length === 0) return "";
|
|
6900
6453
|
return devNotes[devNotes.length - 1].value;
|
|
6901
6454
|
} catch (err) {
|
|
6902
|
-
logger$
|
|
6455
|
+
logger$21.warn({
|
|
6903
6456
|
epicId,
|
|
6904
6457
|
error: err instanceof Error ? err.message : String(err)
|
|
6905
6458
|
}, "Failed to retrieve prev dev notes");
|
|
@@ -6932,7 +6485,7 @@ async function getArchConstraints$3(deps) {
|
|
|
6932
6485
|
const truncatedBody = body.length > 300 ? body.slice(0, 297) + "..." : body;
|
|
6933
6486
|
return `${header}\n${truncatedBody}`;
|
|
6934
6487
|
}).join("\n\n");
|
|
6935
|
-
logger$
|
|
6488
|
+
logger$21.info({
|
|
6936
6489
|
fullLength: full.length,
|
|
6937
6490
|
summarizedLength: summarized.length,
|
|
6938
6491
|
decisions: constraints.length
|
|
@@ -6943,13 +6496,13 @@ async function getArchConstraints$3(deps) {
|
|
|
6943
6496
|
if (archRoot) {
|
|
6944
6497
|
const fallback = readArchConstraintsFromFile(archRoot);
|
|
6945
6498
|
if (fallback) {
|
|
6946
|
-
logger$
|
|
6499
|
+
logger$21.info("Using file-based fallback for architecture constraints (decisions table empty)");
|
|
6947
6500
|
return fallback.length > ARCH_CONSTRAINT_MAX_CHARS ? fallback.slice(0, ARCH_CONSTRAINT_MAX_CHARS) + "\n\n[truncated for token budget]" : fallback;
|
|
6948
6501
|
}
|
|
6949
6502
|
}
|
|
6950
6503
|
return "";
|
|
6951
6504
|
} catch (err) {
|
|
6952
|
-
logger$
|
|
6505
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
6953
6506
|
return "";
|
|
6954
6507
|
}
|
|
6955
6508
|
}
|
|
@@ -7013,7 +6566,7 @@ function readEpicShardFromFile(projectRoot, epicId, storyKey) {
|
|
|
7013
6566
|
}
|
|
7014
6567
|
return "";
|
|
7015
6568
|
} catch (err) {
|
|
7016
|
-
logger$
|
|
6569
|
+
logger$21.warn({
|
|
7017
6570
|
epicId,
|
|
7018
6571
|
error: err instanceof Error ? err.message : String(err)
|
|
7019
6572
|
}, "File-based epic shard fallback failed");
|
|
@@ -7036,7 +6589,7 @@ function readArchConstraintsFromFile(projectRoot) {
|
|
|
7036
6589
|
const content = readFileSync(archPath, "utf-8");
|
|
7037
6590
|
return content.slice(0, 1500);
|
|
7038
6591
|
} catch (err) {
|
|
7039
|
-
logger$
|
|
6592
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "File-based architecture fallback failed");
|
|
7040
6593
|
return "";
|
|
7041
6594
|
}
|
|
7042
6595
|
}
|
|
@@ -7049,7 +6602,7 @@ async function getStoryTemplate(deps) {
|
|
|
7049
6602
|
try {
|
|
7050
6603
|
return await deps.pack.getTemplate("story");
|
|
7051
6604
|
} catch (err) {
|
|
7052
|
-
logger$
|
|
6605
|
+
logger$21.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve story template from pack");
|
|
7053
6606
|
return "";
|
|
7054
6607
|
}
|
|
7055
6608
|
}
|
|
@@ -7086,7 +6639,7 @@ async function isValidStoryFile(filePath) {
|
|
|
7086
6639
|
|
|
7087
6640
|
//#endregion
|
|
7088
6641
|
//#region src/modules/compiled-workflows/git-helpers.ts
|
|
7089
|
-
const logger$
|
|
6642
|
+
const logger$20 = createLogger("compiled-workflows:git-helpers");
|
|
7090
6643
|
/**
|
|
7091
6644
|
* Commit the agent's working-tree output for a dev-story dispatch.
|
|
7092
6645
|
*
|
|
@@ -7130,7 +6683,7 @@ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, working
|
|
|
7130
6683
|
const abs = isAbsolute(p) ? p : resolve$1(workingDir, p);
|
|
7131
6684
|
const rel = relative(workingDir, abs);
|
|
7132
6685
|
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
7133
|
-
logger$
|
|
6686
|
+
logger$20.debug({
|
|
7134
6687
|
path: p,
|
|
7135
6688
|
abs,
|
|
7136
6689
|
workingDir
|
|
@@ -7139,7 +6692,7 @@ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, working
|
|
|
7139
6692
|
}
|
|
7140
6693
|
const segments = rel.replace(/\\/g, "/").split("/");
|
|
7141
6694
|
if (segments.some((s$1) => COMMIT_DENY_SEGMENTS.includes(s$1))) {
|
|
7142
|
-
logger$
|
|
6695
|
+
logger$20.warn({
|
|
7143
6696
|
path: rel,
|
|
7144
6697
|
storyKey
|
|
7145
6698
|
}, "commitDevStoryOutput: denylisted dependency/artifact path excluded from substrate commit");
|
|
@@ -7224,12 +6777,12 @@ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, working
|
|
|
7224
6777
|
timeout: 5e3
|
|
7225
6778
|
}).trim();
|
|
7226
6779
|
} catch (err) {
|
|
7227
|
-
logger$
|
|
6780
|
+
logger$20.warn({
|
|
7228
6781
|
storyKey,
|
|
7229
6782
|
err
|
|
7230
6783
|
}, "commitDevStoryOutput: commit succeeded but rev-parse HEAD failed");
|
|
7231
6784
|
}
|
|
7232
|
-
logger$
|
|
6785
|
+
logger$20.info({
|
|
7233
6786
|
storyKey,
|
|
7234
6787
|
sha,
|
|
7235
6788
|
fileCount: insideWorktree.length
|
|
@@ -7333,7 +6886,7 @@ async function checkpointStoryWorktree(storyKey, reason, workingDir) {
|
|
|
7333
6886
|
timeout: 5e3
|
|
7334
6887
|
}).trim();
|
|
7335
6888
|
} catch {}
|
|
7336
|
-
logger$
|
|
6889
|
+
logger$20.info({
|
|
7337
6890
|
storyKey,
|
|
7338
6891
|
sha,
|
|
7339
6892
|
reason: cleanReason
|
|
@@ -7379,7 +6932,7 @@ function hasCommits(cwd) {
|
|
|
7379
6932
|
*/
|
|
7380
6933
|
async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
7381
6934
|
if (!hasCommits(workingDirectory)) {
|
|
7382
|
-
logger$
|
|
6935
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff");
|
|
7383
6936
|
return "";
|
|
7384
6937
|
}
|
|
7385
6938
|
return runGitCommand(["diff", "HEAD"], workingDirectory, "git-diff-summary");
|
|
@@ -7396,7 +6949,7 @@ async function getGitDiffSummary(workingDirectory = process.cwd()) {
|
|
|
7396
6949
|
*/
|
|
7397
6950
|
async function getGitDiffStatSummary(workingDirectory = process.cwd()) {
|
|
7398
6951
|
if (!hasCommits(workingDirectory)) {
|
|
7399
|
-
logger$
|
|
6952
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat");
|
|
7400
6953
|
return "";
|
|
7401
6954
|
}
|
|
7402
6955
|
return runGitCommand([
|
|
@@ -7445,7 +6998,7 @@ async function getGitDiffStatBetweenCommits(baseCommit, endCommit = "HEAD", work
|
|
|
7445
6998
|
async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
7446
6999
|
if (files.length === 0) return "";
|
|
7447
7000
|
if (!hasCommits(workingDirectory)) {
|
|
7448
|
-
logger$
|
|
7001
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty diff for files");
|
|
7449
7002
|
return "";
|
|
7450
7003
|
}
|
|
7451
7004
|
await stageIntentToAdd(files, workingDirectory);
|
|
@@ -7472,7 +7025,7 @@ async function getGitDiffForFiles(files, workingDirectory = process.cwd()) {
|
|
|
7472
7025
|
async function getGitDiffStatForFiles(files, workingDirectory = process.cwd()) {
|
|
7473
7026
|
if (files.length === 0) return "";
|
|
7474
7027
|
if (!hasCommits(workingDirectory)) {
|
|
7475
|
-
logger$
|
|
7028
|
+
logger$20.debug({ cwd: workingDirectory }, "No commits in repo — returning empty stat for files");
|
|
7476
7029
|
return "";
|
|
7477
7030
|
}
|
|
7478
7031
|
return runGitCommand([
|
|
@@ -7521,7 +7074,7 @@ async function stageIntentToAdd(files, workingDirectory) {
|
|
|
7521
7074
|
if (files.length === 0) return;
|
|
7522
7075
|
const existing = files.filter((f$1) => {
|
|
7523
7076
|
const exists = existsSync(f$1);
|
|
7524
|
-
if (!exists) logger$
|
|
7077
|
+
if (!exists) logger$20.debug({ file: f$1 }, "Skipping nonexistent file in stageIntentToAdd");
|
|
7525
7078
|
return exists;
|
|
7526
7079
|
});
|
|
7527
7080
|
if (existing.length === 0) return;
|
|
@@ -7550,7 +7103,7 @@ async function stageIntentToAdd(files, workingDirectory) {
|
|
|
7550
7103
|
async function recoverStoryFileFromBranch(storyFilePath, workingDirectory) {
|
|
7551
7104
|
const rel = relative(workingDirectory, resolve$1(workingDirectory, storyFilePath));
|
|
7552
7105
|
if (rel.startsWith("..")) {
|
|
7553
|
-
logger$
|
|
7106
|
+
logger$20.warn({
|
|
7554
7107
|
storyFilePath,
|
|
7555
7108
|
workingDirectory
|
|
7556
7109
|
}, "recoverStoryFileFromBranch: path outside the worktree — not recoverable");
|
|
@@ -7562,9 +7115,9 @@ async function recoverStoryFileFromBranch(storyFilePath, workingDirectory) {
|
|
|
7562
7115
|
const abs = resolve$1(workingDirectory, rel);
|
|
7563
7116
|
await mkdir$1(dirname$1(abs), { recursive: true });
|
|
7564
7117
|
await writeFile$1(abs, content, "utf-8");
|
|
7565
|
-
logger$
|
|
7118
|
+
logger$20.warn({ storyFilePath: abs }, "H5.5: story file restored to the working tree from branch HEAD");
|
|
7566
7119
|
} catch (writeErr) {
|
|
7567
|
-
logger$
|
|
7120
|
+
logger$20.warn({
|
|
7568
7121
|
storyFilePath,
|
|
7569
7122
|
err: writeErr
|
|
7570
7123
|
}, "H5.5: recovered story content but could not restore the file (continuing with in-memory content)");
|
|
@@ -7590,7 +7143,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
7590
7143
|
stderr += chunk.toString("utf-8");
|
|
7591
7144
|
});
|
|
7592
7145
|
proc$1.on("error", (err) => {
|
|
7593
|
-
logger$
|
|
7146
|
+
logger$20.warn({
|
|
7594
7147
|
label: logLabel,
|
|
7595
7148
|
cwd,
|
|
7596
7149
|
error: err.message
|
|
@@ -7599,7 +7152,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
7599
7152
|
});
|
|
7600
7153
|
proc$1.on("close", (code) => {
|
|
7601
7154
|
if (code !== 0) {
|
|
7602
|
-
logger$
|
|
7155
|
+
logger$20.warn({
|
|
7603
7156
|
label: logLabel,
|
|
7604
7157
|
cwd,
|
|
7605
7158
|
code,
|
|
@@ -7615,7 +7168,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
7615
7168
|
|
|
7616
7169
|
//#endregion
|
|
7617
7170
|
//#region src/modules/compiled-workflows/story-complexity.ts
|
|
7618
|
-
const logger$
|
|
7171
|
+
const logger$19 = createLogger("compiled-workflows:story-complexity");
|
|
7619
7172
|
/**
|
|
7620
7173
|
* Compute a complexity score from story markdown content.
|
|
7621
7174
|
*
|
|
@@ -7667,7 +7220,7 @@ function resolveFixStoryMaxTurns(complexityScore) {
|
|
|
7667
7220
|
* @param resolvedMaxTurns - Turn limit resolved for this dispatch
|
|
7668
7221
|
*/
|
|
7669
7222
|
function logComplexityResult(storyKey, complexity, resolvedMaxTurns) {
|
|
7670
|
-
logger$
|
|
7223
|
+
logger$19.info({
|
|
7671
7224
|
storyKey,
|
|
7672
7225
|
taskCount: complexity.taskCount,
|
|
7673
7226
|
subtaskCount: complexity.subtaskCount,
|
|
@@ -7940,7 +7493,7 @@ function resolveInstallCommand(projectRoot) {
|
|
|
7940
7493
|
|
|
7941
7494
|
//#endregion
|
|
7942
7495
|
//#region src/modules/compiled-workflows/dev-story.ts
|
|
7943
|
-
const logger$
|
|
7496
|
+
const logger$18 = createLogger("compiled-workflows:dev-story");
|
|
7944
7497
|
/** Default timeout for dev-story dispatches in milliseconds (30 min) */
|
|
7945
7498
|
const DEFAULT_TIMEOUT_MS$2 = 18e5;
|
|
7946
7499
|
/**
|
|
@@ -7952,12 +7505,12 @@ const DEFAULT_TIMEOUT_MS$2 = 18e5;
|
|
|
7952
7505
|
*/
|
|
7953
7506
|
async function runDevStory(deps, params) {
|
|
7954
7507
|
const { storyKey, storyFilePath, taskScope, priorFiles, findingsPrompt: handlerFindingsPrompt } = params;
|
|
7955
|
-
logger$
|
|
7508
|
+
logger$18.info({
|
|
7956
7509
|
storyKey,
|
|
7957
7510
|
storyFilePath
|
|
7958
7511
|
}, "Starting compiled dev-story workflow");
|
|
7959
7512
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("dev-story", deps.tokenCeilings);
|
|
7960
|
-
logger$
|
|
7513
|
+
logger$18.info({
|
|
7961
7514
|
workflow: "dev-story",
|
|
7962
7515
|
ceiling: TOKEN_CEILING,
|
|
7963
7516
|
source: tokenCeilingSource
|
|
@@ -8000,10 +7553,10 @@ async function runDevStory(deps, params) {
|
|
|
8000
7553
|
let template;
|
|
8001
7554
|
try {
|
|
8002
7555
|
template = await deps.pack.getPrompt("dev-story");
|
|
8003
|
-
logger$
|
|
7556
|
+
logger$18.debug({ storyKey }, "Retrieved dev-story prompt template from pack");
|
|
8004
7557
|
} catch (err) {
|
|
8005
7558
|
const error = err instanceof Error ? err.message : String(err);
|
|
8006
|
-
logger$
|
|
7559
|
+
logger$18.error({
|
|
8007
7560
|
storyKey,
|
|
8008
7561
|
error
|
|
8009
7562
|
}, "Failed to retrieve dev-story prompt template");
|
|
@@ -8015,20 +7568,20 @@ async function runDevStory(deps, params) {
|
|
|
8015
7568
|
} catch (err) {
|
|
8016
7569
|
const recovered = await recoverStoryFileFromBranch(storyFilePath, deps.projectRoot ?? process.cwd());
|
|
8017
7570
|
if (recovered !== void 0) {
|
|
8018
|
-
logger$
|
|
7571
|
+
logger$18.warn({
|
|
8019
7572
|
storyKey,
|
|
8020
7573
|
storyFilePath
|
|
8021
7574
|
}, "story file missing from working tree — recovered from branch HEAD (H5.5)");
|
|
8022
7575
|
storyContent = recovered;
|
|
8023
7576
|
} else if (err.code === "ENOENT") {
|
|
8024
|
-
logger$
|
|
7577
|
+
logger$18.error({
|
|
8025
7578
|
storyKey,
|
|
8026
7579
|
storyFilePath
|
|
8027
7580
|
}, "Story file not found");
|
|
8028
7581
|
return makeFailureResult("story_file_not_found");
|
|
8029
7582
|
} else {
|
|
8030
7583
|
const error = err instanceof Error ? err.message : String(err);
|
|
8031
|
-
logger$
|
|
7584
|
+
logger$18.error({
|
|
8032
7585
|
storyKey,
|
|
8033
7586
|
storyFilePath,
|
|
8034
7587
|
error
|
|
@@ -8037,7 +7590,7 @@ async function runDevStory(deps, params) {
|
|
|
8037
7590
|
}
|
|
8038
7591
|
}
|
|
8039
7592
|
if (storyContent.trim().length === 0) {
|
|
8040
|
-
logger$
|
|
7593
|
+
logger$18.error({
|
|
8041
7594
|
storyKey,
|
|
8042
7595
|
storyFilePath
|
|
8043
7596
|
}, "Story file is empty");
|
|
@@ -8045,7 +7598,7 @@ async function runDevStory(deps, params) {
|
|
|
8045
7598
|
}
|
|
8046
7599
|
const staleStatus = detectDeprecatedStatusField(storyContent);
|
|
8047
7600
|
if (staleStatus !== null) {
|
|
8048
|
-
logger$
|
|
7601
|
+
logger$18.warn({
|
|
8049
7602
|
storyFilePath,
|
|
8050
7603
|
staleStatus
|
|
8051
7604
|
}, "Story spec contains deprecated Status field — stripped before dispatch (status is managed by Dolt work graph)");
|
|
@@ -8060,17 +7613,17 @@ async function runDevStory(deps, params) {
|
|
|
8060
7613
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
8061
7614
|
if (testPatternDecisions.length > 0) {
|
|
8062
7615
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
8063
|
-
logger$
|
|
7616
|
+
logger$18.debug({
|
|
8064
7617
|
storyKey,
|
|
8065
7618
|
count: testPatternDecisions.length
|
|
8066
7619
|
}, "Loaded test patterns from decision store");
|
|
8067
7620
|
} else {
|
|
8068
7621
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
8069
|
-
logger$
|
|
7622
|
+
logger$18.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
8070
7623
|
}
|
|
8071
7624
|
} catch (err) {
|
|
8072
7625
|
const error = err instanceof Error ? err.message : String(err);
|
|
8073
|
-
logger$
|
|
7626
|
+
logger$18.warn({
|
|
8074
7627
|
storyKey,
|
|
8075
7628
|
error
|
|
8076
7629
|
}, "Failed to load test patterns — using defaults");
|
|
@@ -8084,7 +7637,7 @@ async function runDevStory(deps, params) {
|
|
|
8084
7637
|
if (deps.repoMapInjector !== void 0) {
|
|
8085
7638
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
8086
7639
|
repoContextContent = injection.text;
|
|
8087
|
-
logger$
|
|
7640
|
+
logger$18.info({
|
|
8088
7641
|
storyKey,
|
|
8089
7642
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
8090
7643
|
symbolCount: injection.symbolCount,
|
|
@@ -8094,7 +7647,7 @@ async function runDevStory(deps, params) {
|
|
|
8094
7647
|
let priorFindingsContent = "";
|
|
8095
7648
|
if (handlerFindingsPrompt !== void 0 && handlerFindingsPrompt.length > 0) {
|
|
8096
7649
|
priorFindingsContent = handlerFindingsPrompt;
|
|
8097
|
-
logger$
|
|
7650
|
+
logger$18.debug({
|
|
8098
7651
|
storyKey,
|
|
8099
7652
|
findingsLen: handlerFindingsPrompt.length
|
|
8100
7653
|
}, "Using pre-computed findings from handler (Story 53-8 AC2)");
|
|
@@ -8106,7 +7659,7 @@ async function runDevStory(deps, params) {
|
|
|
8106
7659
|
});
|
|
8107
7660
|
if (findings.length > 0) {
|
|
8108
7661
|
priorFindingsContent = findings;
|
|
8109
|
-
logger$
|
|
7662
|
+
logger$18.debug({
|
|
8110
7663
|
storyKey,
|
|
8111
7664
|
findingsLen: findings.length
|
|
8112
7665
|
}, "Injecting relevance-scored findings into dev-story prompt");
|
|
@@ -8126,7 +7679,7 @@ async function runDevStory(deps, params) {
|
|
|
8126
7679
|
if (plan.test_categories && plan.test_categories.length > 0) parts.push(`\n### Categories: ${plan.test_categories.join(", ")}`);
|
|
8127
7680
|
if (plan.coverage_notes) parts.push(`\n### Coverage Notes\n${plan.coverage_notes}`);
|
|
8128
7681
|
testPlanContent = parts.join("\n");
|
|
8129
|
-
logger$
|
|
7682
|
+
logger$18.debug({ storyKey }, "Injecting test plan into dev-story prompt");
|
|
8130
7683
|
}
|
|
8131
7684
|
} catch {}
|
|
8132
7685
|
const sections = [
|
|
@@ -8187,7 +7740,7 @@ async function runDevStory(deps, params) {
|
|
|
8187
7740
|
}
|
|
8188
7741
|
];
|
|
8189
7742
|
const { prompt, tokenCount, truncated } = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
8190
|
-
logger$
|
|
7743
|
+
logger$18.info({
|
|
8191
7744
|
storyKey,
|
|
8192
7745
|
tokenCount,
|
|
8193
7746
|
ceiling: TOKEN_CEILING,
|
|
@@ -8211,7 +7764,7 @@ async function runDevStory(deps, params) {
|
|
|
8211
7764
|
dispatchResult = await handle.result;
|
|
8212
7765
|
} catch (err) {
|
|
8213
7766
|
const error = err instanceof Error ? err.message : String(err);
|
|
8214
|
-
logger$
|
|
7767
|
+
logger$18.error({
|
|
8215
7768
|
storyKey,
|
|
8216
7769
|
error
|
|
8217
7770
|
}, "Dispatch threw an unexpected error");
|
|
@@ -8222,11 +7775,11 @@ async function runDevStory(deps, params) {
|
|
|
8222
7775
|
output: dispatchResult.tokenEstimate.output
|
|
8223
7776
|
};
|
|
8224
7777
|
if (dispatchResult.status === "timeout") {
|
|
8225
|
-
logger$
|
|
7778
|
+
logger$18.error({
|
|
8226
7779
|
storyKey,
|
|
8227
7780
|
durationMs: dispatchResult.durationMs
|
|
8228
7781
|
}, "Dev-story dispatch timed out");
|
|
8229
|
-
if (dispatchResult.output.length > 0) logger$
|
|
7782
|
+
if (dispatchResult.output.length > 0) logger$18.info({
|
|
8230
7783
|
storyKey,
|
|
8231
7784
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
8232
7785
|
}, "Partial output before timeout");
|
|
@@ -8236,12 +7789,12 @@ async function runDevStory(deps, params) {
|
|
|
8236
7789
|
};
|
|
8237
7790
|
}
|
|
8238
7791
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
8239
|
-
logger$
|
|
7792
|
+
logger$18.error({
|
|
8240
7793
|
storyKey,
|
|
8241
7794
|
exitCode: dispatchResult.exitCode,
|
|
8242
7795
|
status: dispatchResult.status
|
|
8243
7796
|
}, "Dev-story dispatch failed");
|
|
8244
|
-
if (dispatchResult.output.length > 0) logger$
|
|
7797
|
+
if (dispatchResult.output.length > 0) logger$18.info({
|
|
8245
7798
|
storyKey,
|
|
8246
7799
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
8247
7800
|
}, "Partial output from failed dispatch");
|
|
@@ -8253,7 +7806,7 @@ async function runDevStory(deps, params) {
|
|
|
8253
7806
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
8254
7807
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
8255
7808
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
8256
|
-
logger$
|
|
7809
|
+
logger$18.error({
|
|
8257
7810
|
storyKey,
|
|
8258
7811
|
parseError: details,
|
|
8259
7812
|
rawOutputSnippet: rawSnippet
|
|
@@ -8261,12 +7814,12 @@ async function runDevStory(deps, params) {
|
|
|
8261
7814
|
let filesModified = [];
|
|
8262
7815
|
try {
|
|
8263
7816
|
filesModified = await getGitChangedFiles(deps.projectRoot ?? process.cwd());
|
|
8264
|
-
if (filesModified.length > 0) logger$
|
|
7817
|
+
if (filesModified.length > 0) logger$18.info({
|
|
8265
7818
|
storyKey,
|
|
8266
7819
|
fileCount: filesModified.length
|
|
8267
7820
|
}, "Recovered files_modified from git status (YAML fallback)");
|
|
8268
7821
|
} catch (err) {
|
|
8269
|
-
logger$
|
|
7822
|
+
logger$18.warn({
|
|
8270
7823
|
storyKey,
|
|
8271
7824
|
error: err instanceof Error ? err.message : String(err)
|
|
8272
7825
|
}, "Failed to recover files_modified from git");
|
|
@@ -8283,7 +7836,7 @@ async function runDevStory(deps, params) {
|
|
|
8283
7836
|
};
|
|
8284
7837
|
}
|
|
8285
7838
|
const parsed = dispatchResult.parsed;
|
|
8286
|
-
logger$
|
|
7839
|
+
logger$18.info({
|
|
8287
7840
|
storyKey,
|
|
8288
7841
|
result: parsed.result,
|
|
8289
7842
|
acMet: parsed.ac_met.length
|
|
@@ -8697,7 +8250,7 @@ function resolvesIntoExpected(modifiedFilePath, relativePath, expectedFiles) {
|
|
|
8697
8250
|
|
|
8698
8251
|
//#endregion
|
|
8699
8252
|
//#region src/modules/compiled-workflows/code-review.ts
|
|
8700
|
-
const logger$
|
|
8253
|
+
const logger$17 = createLogger("compiled-workflows:code-review");
|
|
8701
8254
|
/**
|
|
8702
8255
|
* Default fallback result when dispatch fails or times out.
|
|
8703
8256
|
* Uses NEEDS_MINOR_FIXES (not NEEDS_MAJOR_REWORK) so a parse/schema failure
|
|
@@ -8772,14 +8325,14 @@ async function countTestMetrics(filesModified, cwd) {
|
|
|
8772
8325
|
async function runCodeReview(deps, params) {
|
|
8773
8326
|
const { storyKey, storyFilePath, workingDirectory, pipelineRunId, filesModified, previousIssues, buildPassed, baselineCommit } = params;
|
|
8774
8327
|
const cwd = workingDirectory ?? process.cwd();
|
|
8775
|
-
logger$
|
|
8328
|
+
logger$17.debug({
|
|
8776
8329
|
storyKey,
|
|
8777
8330
|
storyFilePath,
|
|
8778
8331
|
cwd,
|
|
8779
8332
|
pipelineRunId
|
|
8780
8333
|
}, "Starting code-review workflow");
|
|
8781
8334
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("code-review", deps.tokenCeilings);
|
|
8782
|
-
logger$
|
|
8335
|
+
logger$17.info({
|
|
8783
8336
|
workflow: "code-review",
|
|
8784
8337
|
ceiling: TOKEN_CEILING,
|
|
8785
8338
|
source: tokenCeilingSource
|
|
@@ -8789,7 +8342,7 @@ async function runCodeReview(deps, params) {
|
|
|
8789
8342
|
template = await deps.pack.getPrompt("code-review");
|
|
8790
8343
|
} catch (err) {
|
|
8791
8344
|
const error = err instanceof Error ? err.message : String(err);
|
|
8792
|
-
logger$
|
|
8345
|
+
logger$17.error({ error }, "Failed to retrieve code-review prompt template");
|
|
8793
8346
|
return defaultFailResult(`Failed to retrieve prompt template: ${error}`, {
|
|
8794
8347
|
input: 0,
|
|
8795
8348
|
output: 0
|
|
@@ -8802,10 +8355,10 @@ async function runCodeReview(deps, params) {
|
|
|
8802
8355
|
const error = err instanceof Error ? err.message : String(err);
|
|
8803
8356
|
const recovered = await recoverStoryFileFromBranch(storyFilePath, cwd);
|
|
8804
8357
|
if (recovered !== void 0) {
|
|
8805
|
-
logger$
|
|
8358
|
+
logger$17.warn({ storyFilePath }, "story file missing from working tree — recovered from branch HEAD (H5.5)");
|
|
8806
8359
|
storyContent = recovered;
|
|
8807
8360
|
} else {
|
|
8808
|
-
logger$
|
|
8361
|
+
logger$17.error({
|
|
8809
8362
|
storyFilePath,
|
|
8810
8363
|
error
|
|
8811
8364
|
}, "Failed to read story file (absent from working tree AND branch HEAD)");
|
|
@@ -8826,12 +8379,12 @@ async function runCodeReview(deps, params) {
|
|
|
8826
8379
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
8827
8380
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
8828
8381
|
gitDiffContent = scopedDiff;
|
|
8829
|
-
logger$
|
|
8382
|
+
logger$17.debug({
|
|
8830
8383
|
fileCount: filesModified.length,
|
|
8831
8384
|
tokenCount: scopedTotal
|
|
8832
8385
|
}, "Using scoped file diff");
|
|
8833
8386
|
} else {
|
|
8834
|
-
logger$
|
|
8387
|
+
logger$17.warn({
|
|
8835
8388
|
estimatedTotal: scopedTotal,
|
|
8836
8389
|
ceiling: TOKEN_CEILING,
|
|
8837
8390
|
fileCount: filesModified.length
|
|
@@ -8845,7 +8398,7 @@ async function runCodeReview(deps, params) {
|
|
|
8845
8398
|
const fullTotal = nonDiffTokens + countTokens(fullDiff);
|
|
8846
8399
|
if (fullTotal <= TOKEN_CEILING) gitDiffContent = fullDiff;
|
|
8847
8400
|
else {
|
|
8848
|
-
logger$
|
|
8401
|
+
logger$17.warn({
|
|
8849
8402
|
estimatedTotal: fullTotal,
|
|
8850
8403
|
ceiling: TOKEN_CEILING
|
|
8851
8404
|
}, "Full git diff would exceed token ceiling — using stat-only summary");
|
|
@@ -8853,7 +8406,7 @@ async function runCodeReview(deps, params) {
|
|
|
8853
8406
|
}
|
|
8854
8407
|
}
|
|
8855
8408
|
if (gitDiffContent.trim().length === 0 && baselineCommit) {
|
|
8856
|
-
logger$
|
|
8409
|
+
logger$17.info({
|
|
8857
8410
|
storyKey,
|
|
8858
8411
|
baselineCommit
|
|
8859
8412
|
}, "Working tree diff empty — diffing against baseline commit");
|
|
@@ -8861,7 +8414,7 @@ async function runCodeReview(deps, params) {
|
|
|
8861
8414
|
const commitTotal = nonDiffTokens + countTokens(commitDiff);
|
|
8862
8415
|
if (commitDiff.trim().length > 0) if (commitTotal <= TOKEN_CEILING) gitDiffContent = commitDiff;
|
|
8863
8416
|
else {
|
|
8864
|
-
logger$
|
|
8417
|
+
logger$17.warn({
|
|
8865
8418
|
estimatedTotal: commitTotal,
|
|
8866
8419
|
ceiling: TOKEN_CEILING
|
|
8867
8420
|
}, "Baseline..HEAD diff exceeds token ceiling — using stat-only summary");
|
|
@@ -8869,7 +8422,7 @@ async function runCodeReview(deps, params) {
|
|
|
8869
8422
|
}
|
|
8870
8423
|
}
|
|
8871
8424
|
if (gitDiffContent.trim().length === 0) {
|
|
8872
|
-
logger$
|
|
8425
|
+
logger$17.info({ storyKey }, "Empty git diff — skipping review with SHIP_IT");
|
|
8873
8426
|
return {
|
|
8874
8427
|
verdict: "SHIP_IT",
|
|
8875
8428
|
issues: 0,
|
|
@@ -8885,7 +8438,7 @@ async function runCodeReview(deps, params) {
|
|
|
8885
8438
|
if (deps.repoMapInjector !== void 0) {
|
|
8886
8439
|
const injection = await deps.repoMapInjector.buildContext(storyContent, deps.maxRepoMapTokens ?? 2e3);
|
|
8887
8440
|
repoContextContent = injection.text;
|
|
8888
|
-
logger$
|
|
8441
|
+
logger$17.info({
|
|
8889
8442
|
storyKey,
|
|
8890
8443
|
repoMapTokens: Math.ceil(injection.text.length / 4),
|
|
8891
8444
|
symbolCount: injection.symbolCount,
|
|
@@ -8905,17 +8458,17 @@ async function runCodeReview(deps, params) {
|
|
|
8905
8458
|
const findings = await getProjectFindings(deps.db);
|
|
8906
8459
|
if (findings.length > 0) {
|
|
8907
8460
|
priorFindingsContent = "Previous reviews found these recurring patterns — pay special attention:\n\n" + findings;
|
|
8908
|
-
logger$
|
|
8461
|
+
logger$17.debug({
|
|
8909
8462
|
storyKey,
|
|
8910
8463
|
findingsLen: findings.length
|
|
8911
8464
|
}, "Injecting prior findings into code-review prompt");
|
|
8912
8465
|
}
|
|
8913
8466
|
} catch {}
|
|
8914
8467
|
const testMetricsContent = await countTestMetrics(filesModified, cwd);
|
|
8915
|
-
if (testMetricsContent) logger$
|
|
8468
|
+
if (testMetricsContent) logger$17.debug({ storyKey }, "Injecting verified test-count metrics into code-review context");
|
|
8916
8469
|
const fileDiffs = gitDiffContent ? parseDiffByFile(gitDiffContent) : void 0;
|
|
8917
8470
|
const scopeAnalysisContent = storyContent && filesModified ? ScopeGuardrail.buildAnalysis(storyContent, filesModified, fileDiffs) : "";
|
|
8918
|
-
if (scopeAnalysisContent) logger$
|
|
8471
|
+
if (scopeAnalysisContent) logger$17.debug({ storyKey }, "Scope analysis detected out-of-scope files");
|
|
8919
8472
|
const buildStatusPrefix = buildPassed === true ? "BUILD STATUS: PASSED — code compiles and passes build verification. Focus on logic correctness, style, and acceptance criteria rather than compilation errors.\n\n" : "";
|
|
8920
8473
|
const sections = [
|
|
8921
8474
|
{
|
|
@@ -8960,11 +8513,11 @@ async function runCodeReview(deps, params) {
|
|
|
8960
8513
|
}
|
|
8961
8514
|
];
|
|
8962
8515
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
8963
|
-
if (assembleResult.truncated) logger$
|
|
8516
|
+
if (assembleResult.truncated) logger$17.warn({
|
|
8964
8517
|
storyKey,
|
|
8965
8518
|
tokenCount: assembleResult.tokenCount
|
|
8966
8519
|
}, "Code-review prompt truncated to fit token ceiling");
|
|
8967
|
-
logger$
|
|
8520
|
+
logger$17.debug({
|
|
8968
8521
|
storyKey,
|
|
8969
8522
|
tokenCount: assembleResult.tokenCount,
|
|
8970
8523
|
truncated: assembleResult.truncated
|
|
@@ -8985,7 +8538,7 @@ async function runCodeReview(deps, params) {
|
|
|
8985
8538
|
dispatchResult = await handle.result;
|
|
8986
8539
|
} catch (err) {
|
|
8987
8540
|
const error = err instanceof Error ? err.message : String(err);
|
|
8988
|
-
logger$
|
|
8541
|
+
logger$17.error({
|
|
8989
8542
|
storyKey,
|
|
8990
8543
|
error
|
|
8991
8544
|
}, "Code-review dispatch threw unexpected error");
|
|
@@ -9001,7 +8554,7 @@ async function runCodeReview(deps, params) {
|
|
|
9001
8554
|
const rawOutput = dispatchResult.output ?? void 0;
|
|
9002
8555
|
if (dispatchResult.status === "failed") {
|
|
9003
8556
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""} ${dispatchResult.output ? `Stderr: ${dispatchResult.output}` : ""}`.trim();
|
|
9004
|
-
logger$
|
|
8557
|
+
logger$17.warn({
|
|
9005
8558
|
storyKey,
|
|
9006
8559
|
exitCode: dispatchResult.exitCode
|
|
9007
8560
|
}, "Code-review dispatch failed");
|
|
@@ -9011,7 +8564,7 @@ async function runCodeReview(deps, params) {
|
|
|
9011
8564
|
};
|
|
9012
8565
|
}
|
|
9013
8566
|
if (dispatchResult.status === "timeout") {
|
|
9014
|
-
logger$
|
|
8567
|
+
logger$17.warn({ storyKey }, "Code-review dispatch timed out");
|
|
9015
8568
|
return {
|
|
9016
8569
|
...defaultFailResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage),
|
|
9017
8570
|
rawOutput
|
|
@@ -9019,7 +8572,7 @@ async function runCodeReview(deps, params) {
|
|
|
9019
8572
|
}
|
|
9020
8573
|
if (dispatchResult.parsed === null) {
|
|
9021
8574
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
9022
|
-
logger$
|
|
8575
|
+
logger$17.warn({
|
|
9023
8576
|
storyKey,
|
|
9024
8577
|
details
|
|
9025
8578
|
}, "Code-review output schema validation failed");
|
|
@@ -9037,7 +8590,7 @@ async function runCodeReview(deps, params) {
|
|
|
9037
8590
|
const parseResult = CodeReviewResultSchema.safeParse(dispatchResult.parsed);
|
|
9038
8591
|
if (!parseResult.success) {
|
|
9039
8592
|
const details = parseResult.error.message;
|
|
9040
|
-
logger$
|
|
8593
|
+
logger$17.warn({
|
|
9041
8594
|
storyKey,
|
|
9042
8595
|
details
|
|
9043
8596
|
}, "Code-review output failed schema validation");
|
|
@@ -9053,13 +8606,13 @@ async function runCodeReview(deps, params) {
|
|
|
9053
8606
|
};
|
|
9054
8607
|
}
|
|
9055
8608
|
const parsed = parseResult.data;
|
|
9056
|
-
if (parsed.agentVerdict !== parsed.verdict) logger$
|
|
8609
|
+
if (parsed.agentVerdict !== parsed.verdict) logger$17.info({
|
|
9057
8610
|
storyKey,
|
|
9058
8611
|
agentVerdict: parsed.agentVerdict,
|
|
9059
8612
|
pipelineVerdict: parsed.verdict,
|
|
9060
8613
|
issues: parsed.issues
|
|
9061
8614
|
}, "Pipeline overrode agent verdict based on issue severities");
|
|
9062
|
-
logger$
|
|
8615
|
+
logger$17.info({
|
|
9063
8616
|
storyKey,
|
|
9064
8617
|
verdict: parsed.verdict,
|
|
9065
8618
|
issues: parsed.issues
|
|
@@ -9085,14 +8638,14 @@ async function getArchConstraints$2(deps) {
|
|
|
9085
8638
|
if (constraints.length === 0) return "";
|
|
9086
8639
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
9087
8640
|
} catch (err) {
|
|
9088
|
-
logger$
|
|
8641
|
+
logger$17.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
9089
8642
|
return "";
|
|
9090
8643
|
}
|
|
9091
8644
|
}
|
|
9092
8645
|
|
|
9093
8646
|
//#endregion
|
|
9094
8647
|
//#region src/modules/compiled-workflows/merge-to-main.ts
|
|
9095
|
-
const logger$
|
|
8648
|
+
const logger$16 = createLogger("compiled-workflows:merge-to-main");
|
|
9096
8649
|
/**
|
|
9097
8650
|
* Execute the merge-to-main phase: merge the story branch into the base branch.
|
|
9098
8651
|
*
|
|
@@ -9112,7 +8665,7 @@ const logger$17 = createLogger("compiled-workflows:merge-to-main");
|
|
|
9112
8665
|
async function runMergeToMain(params) {
|
|
9113
8666
|
const { storyKey, branchName, startBranch, worktreeManager, eventBus, projectRoot } = params;
|
|
9114
8667
|
const mergeStrategy = params.mergeStrategy ?? "ff-only";
|
|
9115
|
-
logger$
|
|
8668
|
+
logger$16.info({
|
|
9116
8669
|
storyKey,
|
|
9117
8670
|
branchName,
|
|
9118
8671
|
startBranch,
|
|
@@ -9120,7 +8673,7 @@ async function runMergeToMain(params) {
|
|
|
9120
8673
|
}, "Starting merge-to-main phase");
|
|
9121
8674
|
const dirtiedFiles = listParentDirtyIntersection(branchName, startBranch, projectRoot);
|
|
9122
8675
|
if (dirtiedFiles.length > 0) {
|
|
9123
|
-
logger$
|
|
8676
|
+
logger$16.warn({
|
|
9124
8677
|
storyKey,
|
|
9125
8678
|
branchName,
|
|
9126
8679
|
dirtiedFiles
|
|
@@ -9133,7 +8686,7 @@ async function runMergeToMain(params) {
|
|
|
9133
8686
|
}
|
|
9134
8687
|
const ffSuccess = tryFfMerge(branchName, projectRoot);
|
|
9135
8688
|
if (ffSuccess) {
|
|
9136
|
-
logger$
|
|
8689
|
+
logger$16.info({
|
|
9137
8690
|
storyKey,
|
|
9138
8691
|
branchName
|
|
9139
8692
|
}, "Fast-forward merge succeeded");
|
|
@@ -9141,7 +8694,7 @@ async function runMergeToMain(params) {
|
|
|
9141
8694
|
return { success: true };
|
|
9142
8695
|
}
|
|
9143
8696
|
if (mergeStrategy === "ff-only") {
|
|
9144
|
-
logger$
|
|
8697
|
+
logger$16.warn({
|
|
9145
8698
|
storyKey,
|
|
9146
8699
|
branchName,
|
|
9147
8700
|
startBranch
|
|
@@ -9151,13 +8704,13 @@ async function runMergeToMain(params) {
|
|
|
9151
8704
|
reason: "ff-only-merge-not-possible"
|
|
9152
8705
|
};
|
|
9153
8706
|
}
|
|
9154
|
-
logger$
|
|
8707
|
+
logger$16.info({
|
|
9155
8708
|
storyKey,
|
|
9156
8709
|
branchName
|
|
9157
8710
|
}, "Fast-forward merge failed — attempting 3-way merge");
|
|
9158
8711
|
const threeWayResult = tryThreeWayMerge(branchName, projectRoot);
|
|
9159
8712
|
if (threeWayResult.success) {
|
|
9160
|
-
logger$
|
|
8713
|
+
logger$16.info({
|
|
9161
8714
|
storyKey,
|
|
9162
8715
|
branchName
|
|
9163
8716
|
}, "3-way merge succeeded");
|
|
@@ -9165,7 +8718,7 @@ async function runMergeToMain(params) {
|
|
|
9165
8718
|
return { success: true };
|
|
9166
8719
|
}
|
|
9167
8720
|
const { conflictingFiles } = threeWayResult;
|
|
9168
|
-
logger$
|
|
8721
|
+
logger$16.warn({
|
|
9169
8722
|
storyKey,
|
|
9170
8723
|
branchName,
|
|
9171
8724
|
conflictingFiles
|
|
@@ -9218,7 +8771,7 @@ function listParentDirtyIntersection(branchName, startBranch, projectRoot) {
|
|
|
9218
8771
|
});
|
|
9219
8772
|
return diffOut.split("\n").filter((f$1) => f$1.trim().length > 0).filter((f$1) => dirty.has(f$1));
|
|
9220
8773
|
} catch (err) {
|
|
9221
|
-
logger$
|
|
8774
|
+
logger$16.warn({ err }, "parent-clean precondition check failed (best-effort) — proceeding to merge");
|
|
9222
8775
|
return [];
|
|
9223
8776
|
}
|
|
9224
8777
|
}
|
|
@@ -9295,7 +8848,7 @@ function tryThreeWayMerge(branchName, projectRoot) {
|
|
|
9295
8848
|
});
|
|
9296
8849
|
conflictingFiles = diffOutput.trim().split("\n").filter((line) => line.length > 0);
|
|
9297
8850
|
} catch (diffErr) {
|
|
9298
|
-
logger$
|
|
8851
|
+
logger$16.warn({ err: diffErr }, "Failed to list conflicting files (best-effort)");
|
|
9299
8852
|
}
|
|
9300
8853
|
try {
|
|
9301
8854
|
execFileSync("git", ["merge", "--abort"], {
|
|
@@ -9307,7 +8860,7 @@ function tryThreeWayMerge(branchName, projectRoot) {
|
|
|
9307
8860
|
]
|
|
9308
8861
|
});
|
|
9309
8862
|
} catch (abortErr) {
|
|
9310
|
-
logger$
|
|
8863
|
+
logger$16.warn({ err: abortErr }, "Failed to abort merge (best-effort)");
|
|
9311
8864
|
}
|
|
9312
8865
|
return {
|
|
9313
8866
|
success: false,
|
|
@@ -9329,12 +8882,12 @@ function tryThreeWayMerge(branchName, projectRoot) {
|
|
|
9329
8882
|
async function cleanupAfterSuccessfulMerge(storyKey, branchName, worktreeManager, _projectRoot) {
|
|
9330
8883
|
try {
|
|
9331
8884
|
await worktreeManager.cleanupWorktree(storyKey);
|
|
9332
|
-
logger$
|
|
8885
|
+
logger$16.info({
|
|
9333
8886
|
storyKey,
|
|
9334
8887
|
branchName
|
|
9335
8888
|
}, "Worktree + branch removed after successful merge");
|
|
9336
8889
|
} catch (worktreeErr) {
|
|
9337
|
-
logger$
|
|
8890
|
+
logger$16.warn({
|
|
9338
8891
|
storyKey,
|
|
9339
8892
|
err: worktreeErr
|
|
9340
8893
|
}, "Failed to remove worktree (best-effort)");
|
|
@@ -9363,7 +8916,7 @@ function createMergeQueue() {
|
|
|
9363
8916
|
|
|
9364
8917
|
//#endregion
|
|
9365
8918
|
//#region src/modules/compiled-workflows/test-plan.ts
|
|
9366
|
-
const logger$
|
|
8919
|
+
const logger$15 = createLogger("compiled-workflows:test-plan");
|
|
9367
8920
|
/** Default timeout for test-plan dispatches in milliseconds (5 min — lightweight call) */
|
|
9368
8921
|
const DEFAULT_TIMEOUT_MS$1 = 3e5;
|
|
9369
8922
|
/**
|
|
@@ -9375,12 +8928,12 @@ const DEFAULT_TIMEOUT_MS$1 = 3e5;
|
|
|
9375
8928
|
*/
|
|
9376
8929
|
async function runTestPlan(deps, params) {
|
|
9377
8930
|
const { storyKey, storyFilePath, pipelineRunId } = params;
|
|
9378
|
-
logger$
|
|
8931
|
+
logger$15.info({
|
|
9379
8932
|
storyKey,
|
|
9380
8933
|
storyFilePath
|
|
9381
8934
|
}, "Starting compiled test-plan workflow");
|
|
9382
8935
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("test-plan", deps.tokenCeilings);
|
|
9383
|
-
logger$
|
|
8936
|
+
logger$15.info({
|
|
9384
8937
|
workflow: "test-plan",
|
|
9385
8938
|
ceiling: TOKEN_CEILING,
|
|
9386
8939
|
source: tokenCeilingSource
|
|
@@ -9388,10 +8941,10 @@ async function runTestPlan(deps, params) {
|
|
|
9388
8941
|
let template;
|
|
9389
8942
|
try {
|
|
9390
8943
|
template = await deps.pack.getPrompt("test-plan");
|
|
9391
|
-
logger$
|
|
8944
|
+
logger$15.debug({ storyKey }, "Retrieved test-plan prompt template from pack");
|
|
9392
8945
|
} catch (err) {
|
|
9393
8946
|
const error = err instanceof Error ? err.message : String(err);
|
|
9394
|
-
logger$
|
|
8947
|
+
logger$15.warn({
|
|
9395
8948
|
storyKey,
|
|
9396
8949
|
error
|
|
9397
8950
|
}, "Failed to retrieve test-plan prompt template");
|
|
@@ -9402,14 +8955,14 @@ async function runTestPlan(deps, params) {
|
|
|
9402
8955
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
9403
8956
|
} catch (err) {
|
|
9404
8957
|
if (err.code === "ENOENT") {
|
|
9405
|
-
logger$
|
|
8958
|
+
logger$15.warn({
|
|
9406
8959
|
storyKey,
|
|
9407
8960
|
storyFilePath
|
|
9408
8961
|
}, "Story file not found for test planning");
|
|
9409
8962
|
return makeTestPlanFailureResult("story_file_not_found");
|
|
9410
8963
|
}
|
|
9411
8964
|
const error = err instanceof Error ? err.message : String(err);
|
|
9412
|
-
logger$
|
|
8965
|
+
logger$15.warn({
|
|
9413
8966
|
storyKey,
|
|
9414
8967
|
storyFilePath,
|
|
9415
8968
|
error
|
|
@@ -9423,13 +8976,13 @@ async function runTestPlan(deps, params) {
|
|
|
9423
8976
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
9424
8977
|
if (testPatternDecisions.length > 0) {
|
|
9425
8978
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
9426
|
-
logger$
|
|
8979
|
+
logger$15.debug({
|
|
9427
8980
|
storyKey,
|
|
9428
8981
|
count: testPatternDecisions.length
|
|
9429
8982
|
}, "Loaded test patterns from decision store");
|
|
9430
8983
|
} else {
|
|
9431
8984
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
9432
|
-
logger$
|
|
8985
|
+
logger$15.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
9433
8986
|
}
|
|
9434
8987
|
} catch {
|
|
9435
8988
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
@@ -9451,7 +9004,7 @@ async function runTestPlan(deps, params) {
|
|
|
9451
9004
|
priority: "optional"
|
|
9452
9005
|
}
|
|
9453
9006
|
], TOKEN_CEILING);
|
|
9454
|
-
logger$
|
|
9007
|
+
logger$15.info({
|
|
9455
9008
|
storyKey,
|
|
9456
9009
|
tokenCount,
|
|
9457
9010
|
ceiling: TOKEN_CEILING,
|
|
@@ -9472,7 +9025,7 @@ async function runTestPlan(deps, params) {
|
|
|
9472
9025
|
dispatchResult = await handle.result;
|
|
9473
9026
|
} catch (err) {
|
|
9474
9027
|
const error = err instanceof Error ? err.message : String(err);
|
|
9475
|
-
logger$
|
|
9028
|
+
logger$15.warn({
|
|
9476
9029
|
storyKey,
|
|
9477
9030
|
error
|
|
9478
9031
|
}, "Test-plan dispatch threw an unexpected error");
|
|
@@ -9483,7 +9036,7 @@ async function runTestPlan(deps, params) {
|
|
|
9483
9036
|
output: dispatchResult.tokenEstimate.output
|
|
9484
9037
|
};
|
|
9485
9038
|
if (dispatchResult.status === "timeout") {
|
|
9486
|
-
logger$
|
|
9039
|
+
logger$15.warn({
|
|
9487
9040
|
storyKey,
|
|
9488
9041
|
durationMs: dispatchResult.durationMs
|
|
9489
9042
|
}, "Test-plan dispatch timed out");
|
|
@@ -9493,7 +9046,7 @@ async function runTestPlan(deps, params) {
|
|
|
9493
9046
|
};
|
|
9494
9047
|
}
|
|
9495
9048
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
9496
|
-
logger$
|
|
9049
|
+
logger$15.warn({
|
|
9497
9050
|
storyKey,
|
|
9498
9051
|
exitCode: dispatchResult.exitCode,
|
|
9499
9052
|
status: dispatchResult.status
|
|
@@ -9505,7 +9058,7 @@ async function runTestPlan(deps, params) {
|
|
|
9505
9058
|
}
|
|
9506
9059
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
9507
9060
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
9508
|
-
logger$
|
|
9061
|
+
logger$15.warn({
|
|
9509
9062
|
storyKey,
|
|
9510
9063
|
parseError: details
|
|
9511
9064
|
}, "Test-plan YAML schema validation failed");
|
|
@@ -9528,19 +9081,19 @@ async function runTestPlan(deps, params) {
|
|
|
9528
9081
|
}),
|
|
9529
9082
|
rationale: `Test plan for ${storyKey}: ${parsed.test_files.length} test files, categories: ${parsed.test_categories.join(", ")}`
|
|
9530
9083
|
});
|
|
9531
|
-
logger$
|
|
9084
|
+
logger$15.info({
|
|
9532
9085
|
storyKey,
|
|
9533
9086
|
fileCount: parsed.test_files.length,
|
|
9534
9087
|
categories: parsed.test_categories
|
|
9535
9088
|
}, "Test plan stored in decision store");
|
|
9536
9089
|
} catch (err) {
|
|
9537
9090
|
const error = err instanceof Error ? err.message : String(err);
|
|
9538
|
-
logger$
|
|
9091
|
+
logger$15.warn({
|
|
9539
9092
|
storyKey,
|
|
9540
9093
|
error
|
|
9541
9094
|
}, "Failed to store test plan in decision store — proceeding anyway");
|
|
9542
9095
|
}
|
|
9543
|
-
logger$
|
|
9096
|
+
logger$15.info({
|
|
9544
9097
|
storyKey,
|
|
9545
9098
|
result: parsed.result
|
|
9546
9099
|
}, "Test-plan workflow completed");
|
|
@@ -9580,14 +9133,14 @@ async function getArchConstraints$1(deps) {
|
|
|
9580
9133
|
if (constraints.length === 0) return "";
|
|
9581
9134
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
9582
9135
|
} catch (err) {
|
|
9583
|
-
logger$
|
|
9136
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints for test-plan — proceeding without them");
|
|
9584
9137
|
return "";
|
|
9585
9138
|
}
|
|
9586
9139
|
}
|
|
9587
9140
|
|
|
9588
9141
|
//#endregion
|
|
9589
9142
|
//#region src/modules/implementation-orchestrator/probe-author-integration.ts
|
|
9590
|
-
const logger$
|
|
9143
|
+
const logger$14 = createLogger("implementation-orchestrator:probe-author");
|
|
9591
9144
|
/**
|
|
9592
9145
|
* Default timeout for probe-author dispatches (10 min).
|
|
9593
9146
|
* obs_2026-05-04_023 layer 2: raised from 300_000 → 600_000 after Story
|
|
@@ -9638,7 +9191,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9638
9191
|
};
|
|
9639
9192
|
const stateIntegratingActive = stateIntegratingEnabled !== false;
|
|
9640
9193
|
if (bypassGates !== true && !detectsEventDrivenAC(epicContent) && !(stateIntegratingActive && detectsStateIntegratingAC(epicContent))) {
|
|
9641
|
-
logger$
|
|
9194
|
+
logger$14.debug({ storyKey }, "probe-author: source AC neither event-driven nor state-integrating — skipping");
|
|
9642
9195
|
emitEvent?.("probe-author:skipped", {
|
|
9643
9196
|
storyKey,
|
|
9644
9197
|
runId: pipelineRunId,
|
|
@@ -9650,7 +9203,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9650
9203
|
try {
|
|
9651
9204
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
9652
9205
|
if (bypassGates !== true && /^## Runtime Probes/m.test(storyContent)) {
|
|
9653
|
-
logger$
|
|
9206
|
+
logger$14.info({ storyKey }, "probe-author: story artifact already has ## Runtime Probes — skipping");
|
|
9654
9207
|
emitEvent?.("probe-author:skipped", {
|
|
9655
9208
|
storyKey,
|
|
9656
9209
|
runId: pipelineRunId,
|
|
@@ -9660,7 +9213,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9660
9213
|
}
|
|
9661
9214
|
} catch (err) {
|
|
9662
9215
|
const error = err instanceof Error ? err.message : String(err);
|
|
9663
|
-
logger$
|
|
9216
|
+
logger$14.warn({
|
|
9664
9217
|
storyKey,
|
|
9665
9218
|
error
|
|
9666
9219
|
}, "probe-author: failed to read story file — falling through");
|
|
@@ -9675,10 +9228,10 @@ async function runProbeAuthor(deps, params) {
|
|
|
9675
9228
|
let template;
|
|
9676
9229
|
try {
|
|
9677
9230
|
template = await deps.pack.getPrompt("probe-author");
|
|
9678
|
-
logger$
|
|
9231
|
+
logger$14.debug({ storyKey }, "probe-author: retrieved prompt template");
|
|
9679
9232
|
} catch (err) {
|
|
9680
9233
|
const error = err instanceof Error ? err.message : String(err);
|
|
9681
|
-
logger$
|
|
9234
|
+
logger$14.warn({
|
|
9682
9235
|
storyKey,
|
|
9683
9236
|
error
|
|
9684
9237
|
}, "probe-author: failed to get prompt template — falling through");
|
|
@@ -9713,13 +9266,13 @@ async function runProbeAuthor(deps, params) {
|
|
|
9713
9266
|
};
|
|
9714
9267
|
let dispatchResult;
|
|
9715
9268
|
try {
|
|
9716
|
-
logger$
|
|
9269
|
+
logger$14.info({ storyKey }, "probe-author: dispatching probe-author agent");
|
|
9717
9270
|
dispatchResult = await doDispatch(basePrompt, DEFAULT_TIMEOUT_MS);
|
|
9718
9271
|
tokenUsage.input += dispatchResult.tokenEstimate.input;
|
|
9719
9272
|
tokenUsage.output += dispatchResult.tokenEstimate.output;
|
|
9720
9273
|
} catch (err) {
|
|
9721
9274
|
const error = err instanceof Error ? err.message : String(err);
|
|
9722
|
-
logger$
|
|
9275
|
+
logger$14.warn({
|
|
9723
9276
|
storyKey,
|
|
9724
9277
|
error
|
|
9725
9278
|
}, "probe-author: dispatch error — falling through to dev-story");
|
|
@@ -9732,7 +9285,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9732
9285
|
}
|
|
9733
9286
|
if (dispatchResult.status === "timeout") {
|
|
9734
9287
|
const elapsedMs = Date.now() - start;
|
|
9735
|
-
logger$
|
|
9288
|
+
logger$14.warn({
|
|
9736
9289
|
storyKey,
|
|
9737
9290
|
elapsedMs
|
|
9738
9291
|
}, "probe-author: dispatch timed out — retrying with 1.5× timeout");
|
|
@@ -9746,13 +9299,13 @@ async function runProbeAuthor(deps, params) {
|
|
|
9746
9299
|
tokenUsage.input += retryResult.tokenEstimate.input;
|
|
9747
9300
|
tokenUsage.output += retryResult.tokenEstimate.output;
|
|
9748
9301
|
if (retryResult.status === "timeout") {
|
|
9749
|
-
logger$
|
|
9302
|
+
logger$14.warn({ storyKey }, "probe-author: retry also timed out — falling through to dev-story");
|
|
9750
9303
|
return makeFailedResult("dispatch_timeout", tokenUsage, start);
|
|
9751
9304
|
}
|
|
9752
9305
|
dispatchResult = retryResult;
|
|
9753
9306
|
} catch (retryErr) {
|
|
9754
9307
|
const error = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
9755
|
-
logger$
|
|
9308
|
+
logger$14.warn({
|
|
9756
9309
|
storyKey,
|
|
9757
9310
|
error
|
|
9758
9311
|
}, "probe-author: retry dispatch error — falling through to dev-story");
|
|
@@ -9761,7 +9314,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9761
9314
|
}
|
|
9762
9315
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
9763
9316
|
const error = `dispatch_failed with exit_code=${dispatchResult.exitCode}`;
|
|
9764
|
-
logger$
|
|
9317
|
+
logger$14.warn({ storyKey }, `probe-author: ${error} — falling through to dev-story`);
|
|
9765
9318
|
emitEvent?.("probe-author:dispatch-error", {
|
|
9766
9319
|
storyKey,
|
|
9767
9320
|
runId: pipelineRunId,
|
|
@@ -9772,7 +9325,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9772
9325
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
9773
9326
|
const parseError = dispatchResult.parseError ?? "parsed result was null";
|
|
9774
9327
|
const rawOutputSnippet = dispatchResult.output.slice(0, 500);
|
|
9775
|
-
logger$
|
|
9328
|
+
logger$14.warn({
|
|
9776
9329
|
storyKey,
|
|
9777
9330
|
parseError,
|
|
9778
9331
|
rawOutputSnippet
|
|
@@ -9789,13 +9342,13 @@ async function runProbeAuthor(deps, params) {
|
|
|
9789
9342
|
tokenUsage.input += retryResult.tokenEstimate.input;
|
|
9790
9343
|
tokenUsage.output += retryResult.tokenEstimate.output;
|
|
9791
9344
|
if (retryResult.parseError !== null || retryResult.parsed === null) {
|
|
9792
|
-
logger$
|
|
9345
|
+
logger$14.warn({ storyKey }, "probe-author: retry still produced invalid YAML — falling through");
|
|
9793
9346
|
return makeFailedResult("invalid_yaml_after_retry", tokenUsage, start);
|
|
9794
9347
|
}
|
|
9795
9348
|
dispatchResult = retryResult;
|
|
9796
9349
|
} catch (retryErr) {
|
|
9797
9350
|
const error = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
9798
|
-
logger$
|
|
9351
|
+
logger$14.warn({
|
|
9799
9352
|
storyKey,
|
|
9800
9353
|
error
|
|
9801
9354
|
}, "probe-author: retry error after invalid YAML — falling through");
|
|
@@ -9806,7 +9359,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9806
9359
|
const probeValidation = RuntimeProbeListSchema.safeParse(parsedOutput.probes);
|
|
9807
9360
|
if (!probeValidation.success) {
|
|
9808
9361
|
const validationError = probeValidation.error.message;
|
|
9809
|
-
logger$
|
|
9362
|
+
logger$14.warn({
|
|
9810
9363
|
storyKey,
|
|
9811
9364
|
validationError
|
|
9812
9365
|
}, "probe-author: probes failed RuntimeProbeListSchema — falling through");
|
|
@@ -9822,7 +9375,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9822
9375
|
probesParsedCount: probes.length
|
|
9823
9376
|
});
|
|
9824
9377
|
if (probes.length === 0) {
|
|
9825
|
-
logger$
|
|
9378
|
+
logger$14.info({ storyKey }, "probe-author: authored empty probes list — no probes needed");
|
|
9826
9379
|
emitEvent?.("probe-author:no-probes-authored", {
|
|
9827
9380
|
storyKey,
|
|
9828
9381
|
runId: pipelineRunId
|
|
@@ -9837,7 +9390,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9837
9390
|
try {
|
|
9838
9391
|
const refreshedContent = await readFile$1(storyFilePath, "utf-8");
|
|
9839
9392
|
if (/^## Runtime Probes/m.test(refreshedContent)) {
|
|
9840
|
-
logger$
|
|
9393
|
+
logger$14.info({ storyKey }, "probe-author: ## Runtime Probes section appeared after dispatch — skipping append (idempotent)");
|
|
9841
9394
|
const dispatchDurationMs$1 = Date.now() - start;
|
|
9842
9395
|
emitEvent?.("probe-author:dispatched", {
|
|
9843
9396
|
storyKey,
|
|
@@ -9856,7 +9409,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9856
9409
|
const tmpPath = join$1(targetDir, `.probe-author-${Date.now()}.tmp.md`);
|
|
9857
9410
|
await writeFile$1(tmpPath, newContent, "utf-8");
|
|
9858
9411
|
await rename(tmpPath, storyFilePath);
|
|
9859
|
-
logger$
|
|
9412
|
+
logger$14.info({
|
|
9860
9413
|
storyKey,
|
|
9861
9414
|
probesCount: probes.length
|
|
9862
9415
|
}, "probe-author: appended ## Runtime Probes section");
|
|
@@ -9868,7 +9421,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9868
9421
|
});
|
|
9869
9422
|
} catch (err) {
|
|
9870
9423
|
const error = err instanceof Error ? err.message : String(err);
|
|
9871
|
-
logger$
|
|
9424
|
+
logger$14.warn({
|
|
9872
9425
|
storyKey,
|
|
9873
9426
|
error
|
|
9874
9427
|
}, "probe-author: failed to append probes — falling through to dev-story");
|
|
@@ -9890,7 +9443,7 @@ async function runProbeAuthor(deps, params) {
|
|
|
9890
9443
|
costUsd,
|
|
9891
9444
|
triggered_by: triggerClass ?? "event-driven"
|
|
9892
9445
|
});
|
|
9893
|
-
logger$
|
|
9446
|
+
logger$14.info({
|
|
9894
9447
|
storyKey,
|
|
9895
9448
|
probesAuthoredCount: probes.length
|
|
9896
9449
|
}, "probe-author: phase complete");
|
|
@@ -9925,7 +9478,7 @@ function estimateDispatchCost$1(input, output) {
|
|
|
9925
9478
|
|
|
9926
9479
|
//#endregion
|
|
9927
9480
|
//#region src/modules/compiled-workflows/test-expansion.ts
|
|
9928
|
-
const logger$
|
|
9481
|
+
const logger$13 = createLogger("compiled-workflows:test-expansion");
|
|
9929
9482
|
function defaultFallbackResult(error, tokenUsage) {
|
|
9930
9483
|
return {
|
|
9931
9484
|
expansion_priority: "low",
|
|
@@ -9955,14 +9508,14 @@ function defaultFallbackResult(error, tokenUsage) {
|
|
|
9955
9508
|
async function runTestExpansion(deps, params) {
|
|
9956
9509
|
const { storyKey, storyFilePath, pipelineRunId, filesModified, workingDirectory } = params;
|
|
9957
9510
|
const cwd = workingDirectory ?? process.cwd();
|
|
9958
|
-
logger$
|
|
9511
|
+
logger$13.debug({
|
|
9959
9512
|
storyKey,
|
|
9960
9513
|
storyFilePath,
|
|
9961
9514
|
cwd,
|
|
9962
9515
|
pipelineRunId
|
|
9963
9516
|
}, "Starting test-expansion workflow");
|
|
9964
9517
|
const { ceiling: TOKEN_CEILING, source: tokenCeilingSource } = getTokenCeiling("test-expansion", deps.tokenCeilings);
|
|
9965
|
-
logger$
|
|
9518
|
+
logger$13.info({
|
|
9966
9519
|
workflow: "test-expansion",
|
|
9967
9520
|
ceiling: TOKEN_CEILING,
|
|
9968
9521
|
source: tokenCeilingSource
|
|
@@ -9972,7 +9525,7 @@ async function runTestExpansion(deps, params) {
|
|
|
9972
9525
|
template = await deps.pack.getPrompt("test-expansion");
|
|
9973
9526
|
} catch (err) {
|
|
9974
9527
|
const error = err instanceof Error ? err.message : String(err);
|
|
9975
|
-
logger$
|
|
9528
|
+
logger$13.warn({ error }, "Failed to retrieve test-expansion prompt template");
|
|
9976
9529
|
return defaultFallbackResult(`Failed to retrieve prompt template: ${error}`, {
|
|
9977
9530
|
input: 0,
|
|
9978
9531
|
output: 0
|
|
@@ -9983,7 +9536,7 @@ async function runTestExpansion(deps, params) {
|
|
|
9983
9536
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
9984
9537
|
} catch (err) {
|
|
9985
9538
|
const error = err instanceof Error ? err.message : String(err);
|
|
9986
|
-
logger$
|
|
9539
|
+
logger$13.warn({
|
|
9987
9540
|
storyFilePath,
|
|
9988
9541
|
error
|
|
9989
9542
|
}, "Failed to read story file");
|
|
@@ -9999,13 +9552,13 @@ async function runTestExpansion(deps, params) {
|
|
|
9999
9552
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
10000
9553
|
if (testPatternDecisions.length > 0) {
|
|
10001
9554
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
10002
|
-
logger$
|
|
9555
|
+
logger$13.debug({
|
|
10003
9556
|
storyKey,
|
|
10004
9557
|
count: testPatternDecisions.length
|
|
10005
9558
|
}, "Loaded test patterns from decision store");
|
|
10006
9559
|
} else {
|
|
10007
9560
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
10008
|
-
logger$
|
|
9561
|
+
logger$13.debug({ storyKey }, "No test-pattern decisions — using stack-aware defaults");
|
|
10009
9562
|
}
|
|
10010
9563
|
} catch {
|
|
10011
9564
|
testPatternsContent = resolveDefaultTestPatterns(deps.projectRoot);
|
|
@@ -10020,12 +9573,12 @@ async function runTestExpansion(deps, params) {
|
|
|
10020
9573
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
10021
9574
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
10022
9575
|
gitDiffContent = scopedDiff;
|
|
10023
|
-
logger$
|
|
9576
|
+
logger$13.debug({
|
|
10024
9577
|
fileCount: filesModified.length,
|
|
10025
9578
|
tokenCount: scopedTotal
|
|
10026
9579
|
}, "Using scoped file diff");
|
|
10027
9580
|
} else {
|
|
10028
|
-
logger$
|
|
9581
|
+
logger$13.warn({
|
|
10029
9582
|
estimatedTotal: scopedTotal,
|
|
10030
9583
|
ceiling: TOKEN_CEILING,
|
|
10031
9584
|
fileCount: filesModified.length
|
|
@@ -10033,7 +9586,7 @@ async function runTestExpansion(deps, params) {
|
|
|
10033
9586
|
gitDiffContent = await getGitDiffStatForFiles(filesModified, cwd);
|
|
10034
9587
|
}
|
|
10035
9588
|
} catch (err) {
|
|
10036
|
-
logger$
|
|
9589
|
+
logger$13.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to get git diff — proceeding with empty diff");
|
|
10037
9590
|
}
|
|
10038
9591
|
const sections = [
|
|
10039
9592
|
{
|
|
@@ -10058,11 +9611,11 @@ async function runTestExpansion(deps, params) {
|
|
|
10058
9611
|
}
|
|
10059
9612
|
];
|
|
10060
9613
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
10061
|
-
if (assembleResult.truncated) logger$
|
|
9614
|
+
if (assembleResult.truncated) logger$13.warn({
|
|
10062
9615
|
storyKey,
|
|
10063
9616
|
tokenCount: assembleResult.tokenCount
|
|
10064
9617
|
}, "Test-expansion prompt truncated to fit token ceiling");
|
|
10065
|
-
logger$
|
|
9618
|
+
logger$13.debug({
|
|
10066
9619
|
storyKey,
|
|
10067
9620
|
tokenCount: assembleResult.tokenCount,
|
|
10068
9621
|
truncated: assembleResult.truncated
|
|
@@ -10082,7 +9635,7 @@ async function runTestExpansion(deps, params) {
|
|
|
10082
9635
|
dispatchResult = await handle.result;
|
|
10083
9636
|
} catch (err) {
|
|
10084
9637
|
const error = err instanceof Error ? err.message : String(err);
|
|
10085
|
-
logger$
|
|
9638
|
+
logger$13.warn({
|
|
10086
9639
|
storyKey,
|
|
10087
9640
|
error
|
|
10088
9641
|
}, "Test-expansion dispatch threw unexpected error");
|
|
@@ -10097,19 +9650,19 @@ async function runTestExpansion(deps, params) {
|
|
|
10097
9650
|
};
|
|
10098
9651
|
if (dispatchResult.status === "failed") {
|
|
10099
9652
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""}`.trim();
|
|
10100
|
-
logger$
|
|
9653
|
+
logger$13.warn({
|
|
10101
9654
|
storyKey,
|
|
10102
9655
|
exitCode: dispatchResult.exitCode
|
|
10103
9656
|
}, "Test-expansion dispatch failed");
|
|
10104
9657
|
return defaultFallbackResult(errorMsg, tokenUsage);
|
|
10105
9658
|
}
|
|
10106
9659
|
if (dispatchResult.status === "timeout") {
|
|
10107
|
-
logger$
|
|
9660
|
+
logger$13.warn({ storyKey }, "Test-expansion dispatch timed out");
|
|
10108
9661
|
return defaultFallbackResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage);
|
|
10109
9662
|
}
|
|
10110
9663
|
if (dispatchResult.parsed === null) {
|
|
10111
9664
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
10112
|
-
logger$
|
|
9665
|
+
logger$13.warn({
|
|
10113
9666
|
storyKey,
|
|
10114
9667
|
details
|
|
10115
9668
|
}, "Test-expansion output has no parseable YAML");
|
|
@@ -10118,14 +9671,14 @@ async function runTestExpansion(deps, params) {
|
|
|
10118
9671
|
const parseResult = TestExpansionResultSchema.safeParse(dispatchResult.parsed);
|
|
10119
9672
|
if (!parseResult.success) {
|
|
10120
9673
|
const details = parseResult.error.message;
|
|
10121
|
-
logger$
|
|
9674
|
+
logger$13.warn({
|
|
10122
9675
|
storyKey,
|
|
10123
9676
|
details
|
|
10124
9677
|
}, "Test-expansion output failed schema validation");
|
|
10125
9678
|
return defaultFallbackResult(`schema_validation_failed: ${details}`, tokenUsage);
|
|
10126
9679
|
}
|
|
10127
9680
|
const parsed = parseResult.data;
|
|
10128
|
-
logger$
|
|
9681
|
+
logger$13.info({
|
|
10129
9682
|
storyKey,
|
|
10130
9683
|
expansion_priority: parsed.expansion_priority,
|
|
10131
9684
|
coverage_gaps: parsed.coverage_gaps.length,
|
|
@@ -10150,14 +9703,14 @@ async function getArchConstraints(deps) {
|
|
|
10150
9703
|
if (constraints.length === 0) return "";
|
|
10151
9704
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
10152
9705
|
} catch (err) {
|
|
10153
|
-
logger$
|
|
9706
|
+
logger$13.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
10154
9707
|
return "";
|
|
10155
9708
|
}
|
|
10156
9709
|
}
|
|
10157
9710
|
|
|
10158
9711
|
//#endregion
|
|
10159
9712
|
//#region src/modules/compiled-workflows/probe-author.ts
|
|
10160
|
-
const logger$
|
|
9713
|
+
const logger$12 = createLogger("compiled-workflows:probe-author");
|
|
10161
9714
|
/**
|
|
10162
9715
|
* Default initial timeout: 10 min. Override via SUBSTRATE_PROBE_AUTHOR_TIMEOUT_MS (ms).
|
|
10163
9716
|
* Story 65-7: raised from 300 s to 600 s to reduce infra-timeout false negatives.
|
|
@@ -10607,7 +10160,7 @@ function detectConflictGroupsWithContracts(storyKeys, config, declarations) {
|
|
|
10607
10160
|
|
|
10608
10161
|
//#endregion
|
|
10609
10162
|
//#region src/modules/implementation-orchestrator/seed-methodology-context.ts
|
|
10610
|
-
const logger$
|
|
10163
|
+
const logger$11 = createLogger("implementation-orchestrator:seed");
|
|
10611
10164
|
/** Max chars for the architecture summary seeded into decisions */
|
|
10612
10165
|
const MAX_ARCH_CHARS = 6e3;
|
|
10613
10166
|
/** Max chars per epic-shard decision value (per-story or per-epic fallback) */
|
|
@@ -10641,12 +10194,12 @@ async function seedMethodologyContext(db, projectRoot) {
|
|
|
10641
10194
|
const testCount = await seedTestPatterns(db, projectRoot);
|
|
10642
10195
|
if (testCount === -1) result.skippedCategories.push("test-patterns");
|
|
10643
10196
|
else result.decisionsCreated += testCount;
|
|
10644
|
-
logger$
|
|
10197
|
+
logger$11.info({
|
|
10645
10198
|
decisionsCreated: result.decisionsCreated,
|
|
10646
10199
|
skippedCategories: result.skippedCategories
|
|
10647
10200
|
}, "Methodology context seeding complete");
|
|
10648
10201
|
} catch (err) {
|
|
10649
|
-
logger$
|
|
10202
|
+
logger$11.warn({ error: err instanceof Error ? err.message : String(err) }, "Methodology context seeding failed (non-fatal)");
|
|
10650
10203
|
}
|
|
10651
10204
|
return result;
|
|
10652
10205
|
}
|
|
@@ -10690,7 +10243,7 @@ async function seedArchitecture(db, projectRoot) {
|
|
|
10690
10243
|
});
|
|
10691
10244
|
count = 1;
|
|
10692
10245
|
}
|
|
10693
|
-
logger$
|
|
10246
|
+
logger$11.debug({ count }, "Seeded architecture decisions");
|
|
10694
10247
|
return count;
|
|
10695
10248
|
}
|
|
10696
10249
|
/**
|
|
@@ -10714,11 +10267,11 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
10714
10267
|
const storedHashDecision = implementationDecisions.find((d) => d.category === "epic-shard-hash" && d.key === "epics-file");
|
|
10715
10268
|
const storedHash = storedHashDecision?.value;
|
|
10716
10269
|
if (storedHash === currentHash) {
|
|
10717
|
-
logger$
|
|
10270
|
+
logger$11.debug({ hash: currentHash }, "Epic shards up-to-date (hash unchanged) — skipping re-seed");
|
|
10718
10271
|
return -1;
|
|
10719
10272
|
}
|
|
10720
10273
|
if (implementationDecisions.some((d) => d.category === "epic-shard")) {
|
|
10721
|
-
logger$
|
|
10274
|
+
logger$11.debug({
|
|
10722
10275
|
storedHash,
|
|
10723
10276
|
currentHash
|
|
10724
10277
|
}, "Epics file changed — deleting stale epic-shard decisions");
|
|
@@ -10730,7 +10283,7 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
10730
10283
|
for (const shard of shards) {
|
|
10731
10284
|
const subsections = parseStorySubsections(shard.epicId, shard.content);
|
|
10732
10285
|
for (const subsection of subsections) {
|
|
10733
|
-
if (subsection.content.length > MAX_EPIC_SHARD_CHARS) logger$
|
|
10286
|
+
if (subsection.content.length > MAX_EPIC_SHARD_CHARS) logger$11.warn({
|
|
10734
10287
|
epicId: shard.epicId,
|
|
10735
10288
|
storyKey: subsection.key,
|
|
10736
10289
|
originalLength: subsection.content.length,
|
|
@@ -10738,7 +10291,7 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
10738
10291
|
droppedChars: subsection.content.length - MAX_EPIC_SHARD_CHARS
|
|
10739
10292
|
}, `Epic shard for ${subsection.key} exceeded ${MAX_EPIC_SHARD_CHARS}-char cap and was truncated; tail content lost from decisions store. Consider splitting the story or raising MAX_EPIC_SHARD_CHARS.`);
|
|
10740
10293
|
if (seenKeys.has(subsection.key)) {
|
|
10741
|
-
logger$
|
|
10294
|
+
logger$11.warn({
|
|
10742
10295
|
epicId: shard.epicId,
|
|
10743
10296
|
storyKey: subsection.key,
|
|
10744
10297
|
droppedContentLength: subsection.content.length
|
|
@@ -10766,7 +10319,7 @@ async function seedEpicShards(db, projectRoot) {
|
|
|
10766
10319
|
value: currentHash,
|
|
10767
10320
|
rationale: "SHA-256 hash of epics file content for change detection"
|
|
10768
10321
|
});
|
|
10769
|
-
logger$
|
|
10322
|
+
logger$11.debug({
|
|
10770
10323
|
count,
|
|
10771
10324
|
hash: currentHash
|
|
10772
10325
|
}, "Seeded epic shard decisions");
|
|
@@ -10790,7 +10343,7 @@ async function seedTestPatterns(db, projectRoot) {
|
|
|
10790
10343
|
value: patterns.slice(0, MAX_TEST_PATTERNS_CHARS),
|
|
10791
10344
|
rationale: "Detected from project configuration at orchestrator startup"
|
|
10792
10345
|
});
|
|
10793
|
-
logger$
|
|
10346
|
+
logger$11.debug("Seeded test patterns decision");
|
|
10794
10347
|
return 1;
|
|
10795
10348
|
}
|
|
10796
10349
|
/**
|
|
@@ -11280,7 +10833,7 @@ function findArtifact(projectRoot, candidates) {
|
|
|
11280
10833
|
|
|
11281
10834
|
//#endregion
|
|
11282
10835
|
//#region src/modules/implementation-orchestrator/package-snapshot.ts
|
|
11283
|
-
const logger$
|
|
10836
|
+
const logger$10 = createLogger("package-snapshot");
|
|
11284
10837
|
/**
|
|
11285
10838
|
* Discover all package.json paths in a workspace monorepo.
|
|
11286
10839
|
* Checks the `workspaces` field in root package.json,
|
|
@@ -11372,7 +10925,7 @@ function restorePackageSnapshot(snapshot, options) {
|
|
|
11372
10925
|
writeFileSync(filePath, content, "utf-8");
|
|
11373
10926
|
filesRestored++;
|
|
11374
10927
|
} catch (err) {
|
|
11375
|
-
logger$
|
|
10928
|
+
logger$10.warn({
|
|
11376
10929
|
filePath,
|
|
11377
10930
|
err
|
|
11378
10931
|
}, "Failed to restore file from snapshot");
|
|
@@ -11383,7 +10936,7 @@ function restorePackageSnapshot(snapshot, options) {
|
|
|
11383
10936
|
encoding: "utf-8",
|
|
11384
10937
|
stdio: "pipe"
|
|
11385
10938
|
});
|
|
11386
|
-
logger$
|
|
10939
|
+
logger$10.info({
|
|
11387
10940
|
filesRestored,
|
|
11388
10941
|
installCommand: snapshot.installCommand
|
|
11389
10942
|
}, "Package snapshot restored successfully");
|
|
@@ -11394,7 +10947,7 @@ function restorePackageSnapshot(snapshot, options) {
|
|
|
11394
10947
|
};
|
|
11395
10948
|
} catch (err) {
|
|
11396
10949
|
const exitCode = err.status ?? 1;
|
|
11397
|
-
logger$
|
|
10950
|
+
logger$10.warn({
|
|
11398
10951
|
filesRestored,
|
|
11399
10952
|
exitCode,
|
|
11400
10953
|
err
|
|
@@ -11743,7 +11296,7 @@ const RecommendationSchema = z.object({
|
|
|
11743
11296
|
|
|
11744
11297
|
//#endregion
|
|
11745
11298
|
//#region src/modules/telemetry/adapter-persistence.ts
|
|
11746
|
-
const logger$
|
|
11299
|
+
const logger$9 = createLogger("telemetry:adapter-persistence");
|
|
11747
11300
|
/**
|
|
11748
11301
|
* Concrete DatabaseAdapter-backed telemetry persistence.
|
|
11749
11302
|
*
|
|
@@ -11797,7 +11350,7 @@ var AdapterTelemetryPersistence = class {
|
|
|
11797
11350
|
]);
|
|
11798
11351
|
}
|
|
11799
11352
|
});
|
|
11800
|
-
logger$
|
|
11353
|
+
logger$9.debug({
|
|
11801
11354
|
storyKey,
|
|
11802
11355
|
count: turns.length
|
|
11803
11356
|
}, "Stored turn analysis");
|
|
@@ -11869,7 +11422,7 @@ var AdapterTelemetryPersistence = class {
|
|
|
11869
11422
|
score.taskType ?? null,
|
|
11870
11423
|
score.phase ?? null
|
|
11871
11424
|
]);
|
|
11872
|
-
logger$
|
|
11425
|
+
logger$9.debug({
|
|
11873
11426
|
storyKey: score.storyKey,
|
|
11874
11427
|
compositeScore: score.compositeScore
|
|
11875
11428
|
}, "Stored efficiency score");
|
|
@@ -11937,7 +11490,7 @@ var AdapterTelemetryPersistence = class {
|
|
|
11937
11490
|
]);
|
|
11938
11491
|
}
|
|
11939
11492
|
});
|
|
11940
|
-
logger$
|
|
11493
|
+
logger$9.debug({
|
|
11941
11494
|
storyKey,
|
|
11942
11495
|
count: recs.length
|
|
11943
11496
|
}, "Saved recommendations");
|
|
@@ -12014,7 +11567,7 @@ var AdapterTelemetryPersistence = class {
|
|
|
12014
11567
|
stat$2.trend
|
|
12015
11568
|
]);
|
|
12016
11569
|
});
|
|
12017
|
-
logger$
|
|
11570
|
+
logger$9.debug({
|
|
12018
11571
|
storyKey,
|
|
12019
11572
|
count: stats.length
|
|
12020
11573
|
}, "Stored category stats");
|
|
@@ -12057,7 +11610,7 @@ var AdapterTelemetryPersistence = class {
|
|
|
12057
11610
|
JSON.stringify(consumer.topInvocations)
|
|
12058
11611
|
]);
|
|
12059
11612
|
});
|
|
12060
|
-
logger$
|
|
11613
|
+
logger$9.debug({
|
|
12061
11614
|
storyKey,
|
|
12062
11615
|
count: consumers.length
|
|
12063
11616
|
}, "Stored consumer stats");
|
|
@@ -12089,14 +11642,14 @@ var AdapterTelemetryPersistence = class {
|
|
|
12089
11642
|
await adapter.query("DELETE FROM category_stats WHERE story_key = ?", [storyKey]);
|
|
12090
11643
|
await adapter.query("DELETE FROM consumer_stats WHERE story_key = ?", [storyKey]);
|
|
12091
11644
|
});
|
|
12092
|
-
logger$
|
|
11645
|
+
logger$9.debug({ storyKey }, "Purged stale telemetry data for story");
|
|
12093
11646
|
}
|
|
12094
11647
|
/**
|
|
12095
11648
|
* Record a named span with arbitrary attributes.
|
|
12096
11649
|
* Currently logs the span at debug level; no DB persistence.
|
|
12097
11650
|
*/
|
|
12098
11651
|
recordSpan(span) {
|
|
12099
|
-
logger$
|
|
11652
|
+
logger$9.debug({ span }, "recordSpan");
|
|
12100
11653
|
}
|
|
12101
11654
|
};
|
|
12102
11655
|
|
|
@@ -12171,7 +11724,7 @@ var TelemetryPersistence = class {
|
|
|
12171
11724
|
|
|
12172
11725
|
//#endregion
|
|
12173
11726
|
//#region src/modules/telemetry/telemetry-advisor.ts
|
|
12174
|
-
const logger$
|
|
11727
|
+
const logger$8 = createLogger("telemetry-advisor");
|
|
12175
11728
|
/**
|
|
12176
11729
|
* Reads telemetry efficiency data to support retry gate decisions.
|
|
12177
11730
|
*/
|
|
@@ -12193,7 +11746,7 @@ var TelemetryAdvisor = class {
|
|
|
12193
11746
|
try {
|
|
12194
11747
|
const score = await this._persistence.getEfficiencyScore(storyKey);
|
|
12195
11748
|
if (score === null) {
|
|
12196
|
-
logger$
|
|
11749
|
+
logger$8.debug({ storyKey }, "No efficiency score found for story");
|
|
12197
11750
|
return null;
|
|
12198
11751
|
}
|
|
12199
11752
|
return {
|
|
@@ -12208,7 +11761,7 @@ var TelemetryAdvisor = class {
|
|
|
12208
11761
|
coldStartTurnsExcluded: score.coldStartTurnsExcluded ?? 0
|
|
12209
11762
|
};
|
|
12210
11763
|
} catch (err) {
|
|
12211
|
-
logger$
|
|
11764
|
+
logger$8.warn({
|
|
12212
11765
|
err,
|
|
12213
11766
|
storyKey
|
|
12214
11767
|
}, "Failed to retrieve efficiency score");
|
|
@@ -12245,7 +11798,7 @@ var TelemetryAdvisor = class {
|
|
|
12245
11798
|
merged.sort((a, b) => (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3));
|
|
12246
11799
|
return merged;
|
|
12247
11800
|
} catch (err) {
|
|
12248
|
-
logger$
|
|
11801
|
+
logger$8.warn({ err }, "Failed to retrieve recommendations for run — returning empty");
|
|
12249
11802
|
return [];
|
|
12250
11803
|
}
|
|
12251
11804
|
}
|
|
@@ -12275,7 +11828,7 @@ var TelemetryAdvisor = class {
|
|
|
12275
11828
|
const lines = actionable.map((r) => `OPTIMIZATION (${r.severity}): ${r.title}. ${r.description}`);
|
|
12276
11829
|
const full = lines.join("\n");
|
|
12277
11830
|
if (full.length <= MAX_CHARS$1) {
|
|
12278
|
-
logger$
|
|
11831
|
+
logger$8.debug({
|
|
12279
11832
|
count: actionable.length,
|
|
12280
11833
|
chars: full.length
|
|
12281
11834
|
}, "Formatting optimization directives");
|
|
@@ -12283,7 +11836,7 @@ var TelemetryAdvisor = class {
|
|
|
12283
11836
|
}
|
|
12284
11837
|
const cutAt = full.lastIndexOf(" ", MAX_CHARS$1);
|
|
12285
11838
|
const truncated = (cutAt > 0 ? full.slice(0, cutAt) : full.slice(0, MAX_CHARS$1)) + "…";
|
|
12286
|
-
logger$
|
|
11839
|
+
logger$8.debug({
|
|
12287
11840
|
count: actionable.length,
|
|
12288
11841
|
chars: truncated.length
|
|
12289
11842
|
}, "Optimization directives truncated to budget");
|
|
@@ -12297,171 +11850,6 @@ function createTelemetryAdvisor(deps) {
|
|
|
12297
11850
|
return new TelemetryAdvisor(deps);
|
|
12298
11851
|
}
|
|
12299
11852
|
|
|
12300
|
-
//#endregion
|
|
12301
|
-
//#region src/modules/compiled-workflows/acceptance-judge.ts
|
|
12302
|
-
const logger$8 = createLogger("compiled-workflows:acceptance-judge");
|
|
12303
|
-
/** Cap per-artifact content injected into the prompt (chars). */
|
|
12304
|
-
const ARTIFACT_CONTENT_CAP = 16e3;
|
|
12305
|
-
function renderEndStates(journey) {
|
|
12306
|
-
return journey.end_states.map((es) => `- id: ${es.id}\n given: ${es.given}\n walk: ${es.walk}\n then: ${es.then}`).join("\n");
|
|
12307
|
-
}
|
|
12308
|
-
async function renderArtifactContents(artifactsDir, artifacts) {
|
|
12309
|
-
const blocks = [];
|
|
12310
|
-
for (const rel of artifacts) {
|
|
12311
|
-
let content;
|
|
12312
|
-
try {
|
|
12313
|
-
content = await readFile$1(join$1(artifactsDir, rel), "utf-8");
|
|
12314
|
-
} catch {
|
|
12315
|
-
blocks.push(`--- ${rel} ---\n(unreadable or binary — judge from the other artifacts)`);
|
|
12316
|
-
continue;
|
|
12317
|
-
}
|
|
12318
|
-
const truncated = content.length > ARTIFACT_CONTENT_CAP;
|
|
12319
|
-
blocks.push(`--- ${rel}${truncated ? ` (truncated to first ${String(ARTIFACT_CONTENT_CAP)} chars)` : ""} ---\n` + content.slice(0, ARTIFACT_CONTENT_CAP));
|
|
12320
|
-
}
|
|
12321
|
-
return blocks.join("\n\n");
|
|
12322
|
-
}
|
|
12323
|
-
/** Validate verdict completeness: every end-state exactly once, no unknown ids. */
|
|
12324
|
-
function validateVerdictCoverage(journey, verdicts) {
|
|
12325
|
-
const expected = new Set(journey.end_states.map((es) => es.id));
|
|
12326
|
-
const seen = new Set();
|
|
12327
|
-
for (const v of verdicts) {
|
|
12328
|
-
if (!expected.has(v.end_state_id)) return `verdict for unknown end-state id "${v.end_state_id}"`;
|
|
12329
|
-
if (seen.has(v.end_state_id)) return `duplicate verdict for end-state "${v.end_state_id}"`;
|
|
12330
|
-
seen.add(v.end_state_id);
|
|
12331
|
-
}
|
|
12332
|
-
const missing = [...expected].filter((id) => !seen.has(id));
|
|
12333
|
-
if (missing.length > 0) return `missing verdict(s) for end-state(s): ${missing.join(", ")}`;
|
|
12334
|
-
return void 0;
|
|
12335
|
-
}
|
|
12336
|
-
async function runAcceptanceJudge(deps, params) {
|
|
12337
|
-
const { journey, artifactsDir, artifacts, storyKey } = params;
|
|
12338
|
-
let template;
|
|
12339
|
-
try {
|
|
12340
|
-
template = await deps.pack.getPrompt("acceptance-judge");
|
|
12341
|
-
} catch (err) {
|
|
12342
|
-
return {
|
|
12343
|
-
result: "failed",
|
|
12344
|
-
error: `Failed to retrieve acceptance-judge prompt: ${err instanceof Error ? err.message : String(err)}`,
|
|
12345
|
-
tokenUsage: {
|
|
12346
|
-
input: 0,
|
|
12347
|
-
output: 0
|
|
12348
|
-
}
|
|
12349
|
-
};
|
|
12350
|
-
}
|
|
12351
|
-
const artifactContents = await renderArtifactContents(artifactsDir, artifacts);
|
|
12352
|
-
const buildPrompt = (correctivePreamble) => {
|
|
12353
|
-
const { prompt } = assemblePrompt(template, [
|
|
12354
|
-
{
|
|
12355
|
-
name: "journey_id",
|
|
12356
|
-
content: journey.id,
|
|
12357
|
-
priority: "required"
|
|
12358
|
-
},
|
|
12359
|
-
{
|
|
12360
|
-
name: "journey_title",
|
|
12361
|
-
content: journey.title,
|
|
12362
|
-
priority: "required"
|
|
12363
|
-
},
|
|
12364
|
-
{
|
|
12365
|
-
name: "end_states",
|
|
12366
|
-
content: renderEndStates(journey),
|
|
12367
|
-
priority: "required"
|
|
12368
|
-
},
|
|
12369
|
-
{
|
|
12370
|
-
name: "artifact_manifest",
|
|
12371
|
-
content: artifacts.length > 0 ? artifacts.map((a) => `- ${a}`).join("\n") : "(no artifacts)",
|
|
12372
|
-
priority: "required"
|
|
12373
|
-
},
|
|
12374
|
-
{
|
|
12375
|
-
name: "artifact_contents",
|
|
12376
|
-
content: artifactContents,
|
|
12377
|
-
priority: "required"
|
|
12378
|
-
}
|
|
12379
|
-
], getTokenCeiling("acceptance-judge", deps.tokenCeilings).ceiling);
|
|
12380
|
-
return correctivePreamble !== void 0 ? `${correctivePreamble}\n\n${prompt}` : prompt;
|
|
12381
|
-
};
|
|
12382
|
-
let totalTokens = {
|
|
12383
|
-
input: 0,
|
|
12384
|
-
output: 0
|
|
12385
|
-
};
|
|
12386
|
-
let lastProblem = "unknown";
|
|
12387
|
-
for (let attempt = 0; attempt < 2; attempt++) {
|
|
12388
|
-
const prompt = attempt === 0 ? buildPrompt() : buildPrompt(`PREVIOUS ATTEMPT REJECTED: ${lastProblem}. Emit ONLY the YAML block per the Output Contract — every end-state exactly once, every verdict with evidence {artifact, excerpt}.`);
|
|
12389
|
-
const handle = deps.dispatcher.dispatch({
|
|
12390
|
-
prompt,
|
|
12391
|
-
agent: deps.agentId ?? "claude-code",
|
|
12392
|
-
taskType: "acceptance-judge",
|
|
12393
|
-
outputSchema: AcceptanceJudgeResultSchema,
|
|
12394
|
-
maxTurns: 20,
|
|
12395
|
-
workingDirectory: artifactsDir,
|
|
12396
|
-
...deps.otlpEndpoint !== void 0 ? { otlpEndpoint: deps.otlpEndpoint } : {},
|
|
12397
|
-
...storyKey !== void 0 ? { storyKey } : {}
|
|
12398
|
-
});
|
|
12399
|
-
let dispatchResult;
|
|
12400
|
-
try {
|
|
12401
|
-
dispatchResult = await handle.result;
|
|
12402
|
-
} catch (err) {
|
|
12403
|
-
return {
|
|
12404
|
-
result: "failed",
|
|
12405
|
-
error: `Dispatch error: ${err instanceof Error ? err.message : String(err)}`,
|
|
12406
|
-
tokenUsage: totalTokens
|
|
12407
|
-
};
|
|
12408
|
-
}
|
|
12409
|
-
totalTokens = {
|
|
12410
|
-
input: totalTokens.input + dispatchResult.tokenEstimate.input,
|
|
12411
|
-
output: totalTokens.output + dispatchResult.tokenEstimate.output
|
|
12412
|
-
};
|
|
12413
|
-
if (dispatchResult.status === "failed" || dispatchResult.status === "timeout") return {
|
|
12414
|
-
result: "failed",
|
|
12415
|
-
error: `Dispatch status: ${dispatchResult.status}. ${dispatchResult.parseError ?? ""}`.trim(),
|
|
12416
|
-
tokenUsage: totalTokens
|
|
12417
|
-
};
|
|
12418
|
-
const parsed = AcceptanceJudgeResultSchema.safeParse(dispatchResult.parsed);
|
|
12419
|
-
if (!parsed.success) {
|
|
12420
|
-
lastProblem = `output failed schema validation (${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ").slice(0, 500)})`;
|
|
12421
|
-
logger$8.warn({
|
|
12422
|
-
journeyId: journey.id,
|
|
12423
|
-
storyKey,
|
|
12424
|
-
attempt,
|
|
12425
|
-
lastProblem
|
|
12426
|
-
}, "A2.1: judge output invalid");
|
|
12427
|
-
continue;
|
|
12428
|
-
}
|
|
12429
|
-
if (parsed.data.result === "failed") return {
|
|
12430
|
-
result: "failed",
|
|
12431
|
-
error: "acceptance-judge-refused",
|
|
12432
|
-
details: parsed.data.error ?? "judge reported failure without a reason",
|
|
12433
|
-
tokenUsage: totalTokens
|
|
12434
|
-
};
|
|
12435
|
-
const coverageProblem = validateVerdictCoverage(journey, parsed.data.verdicts);
|
|
12436
|
-
if (coverageProblem !== void 0) {
|
|
12437
|
-
lastProblem = coverageProblem;
|
|
12438
|
-
logger$8.warn({
|
|
12439
|
-
journeyId: journey.id,
|
|
12440
|
-
storyKey,
|
|
12441
|
-
attempt,
|
|
12442
|
-
coverageProblem
|
|
12443
|
-
}, "A2.1: judge verdicts incomplete");
|
|
12444
|
-
continue;
|
|
12445
|
-
}
|
|
12446
|
-
logger$8.info({
|
|
12447
|
-
journeyId: journey.id,
|
|
12448
|
-
storyKey,
|
|
12449
|
-
verdicts: parsed.data.verdicts.map((v) => `${v.end_state_id}=${v.verdict}`)
|
|
12450
|
-
}, "A2.1: acceptance judge verdicts accepted");
|
|
12451
|
-
return {
|
|
12452
|
-
result: "success",
|
|
12453
|
-
verdicts: parsed.data.verdicts,
|
|
12454
|
-
tokenUsage: totalTokens
|
|
12455
|
-
};
|
|
12456
|
-
}
|
|
12457
|
-
return {
|
|
12458
|
-
result: "failed",
|
|
12459
|
-
error: "acceptance-judge-invalid",
|
|
12460
|
-
details: `judge produced invalid output twice — last problem: ${lastProblem}`,
|
|
12461
|
-
tokenUsage: totalTokens
|
|
12462
|
-
};
|
|
12463
|
-
}
|
|
12464
|
-
|
|
12465
11853
|
//#endregion
|
|
12466
11854
|
//#region src/modules/implementation-orchestrator/verification-integration.ts
|
|
12467
11855
|
const _logger = createLogger("verification-integration");
|
|
@@ -13767,7 +13155,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13767
13155
|
projectRoot,
|
|
13768
13156
|
...config.worktreeCopyFiles !== void 0 ? { copyFiles: config.worktreeCopyFiles } : {}
|
|
13769
13157
|
}) : void 0);
|
|
13770
|
-
const logger$
|
|
13158
|
+
const logger$26 = createLogger("implementation-orchestrator");
|
|
13771
13159
|
const telemetryAdvisor = db !== void 0 ? createTelemetryAdvisor({ db }) : void 0;
|
|
13772
13160
|
const wgRepo = new WorkGraphRepository(db);
|
|
13773
13161
|
const _wgInProgressWritten = new Set();
|
|
@@ -13795,6 +13183,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13795
13183
|
let _maxConcurrentActual = 0;
|
|
13796
13184
|
let _packageSnapshot;
|
|
13797
13185
|
let _orchestratorStartBranch;
|
|
13186
|
+
let _runStartSha;
|
|
13798
13187
|
let _contractMismatches;
|
|
13799
13188
|
const _costChecker = new CostGovernanceChecker();
|
|
13800
13189
|
let _costWarningEmitted = false;
|
|
@@ -13874,7 +13263,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13874
13263
|
const existingCount = storyState?.retry_count ?? 0;
|
|
13875
13264
|
_storyRetryCount.set(storyKey, existingCount);
|
|
13876
13265
|
} catch (err) {
|
|
13877
|
-
logger$
|
|
13266
|
+
logger$26.warn({
|
|
13878
13267
|
err,
|
|
13879
13268
|
storyKey
|
|
13880
13269
|
}, "initRetryCount: failed to read manifest — starting at 0");
|
|
@@ -13888,7 +13277,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13888
13277
|
const current = _storyRetryCount.get(storyKey) ?? 0;
|
|
13889
13278
|
const next = current + 1;
|
|
13890
13279
|
_storyRetryCount.set(storyKey, next);
|
|
13891
|
-
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$
|
|
13280
|
+
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { retry_count: next }).catch((err) => logger$26.warn({
|
|
13892
13281
|
err,
|
|
13893
13282
|
storyKey
|
|
13894
13283
|
}, "patchStoryState(retry_count) failed — pipeline continues"));
|
|
@@ -13901,7 +13290,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13901
13290
|
const nowMs = Date.now();
|
|
13902
13291
|
for (const [phase, startMs] of starts) {
|
|
13903
13292
|
const endMs = ends?.get(phase);
|
|
13904
|
-
if (endMs === void 0) logger$
|
|
13293
|
+
if (endMs === void 0) logger$26.warn({
|
|
13905
13294
|
storyKey,
|
|
13906
13295
|
phase
|
|
13907
13296
|
}, "Phase has no end time — story may have errored mid-phase. Duration capped to now() and may be inflated.");
|
|
@@ -13918,7 +13307,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13918
13307
|
const wallClockSeconds = startedAt ? Math.round((new Date(completedAt).getTime() - new Date(startedAt).getTime()) / 1e3) : 0;
|
|
13919
13308
|
const wallClockMs = startedAt ? new Date(completedAt).getTime() - new Date(startedAt).getTime() : 0;
|
|
13920
13309
|
const tokenAgg = await aggregateTokenUsageForStory(db, config.pipelineRunId, storyKey);
|
|
13921
|
-
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$
|
|
13310
|
+
if (runManifest !== null) runManifest.patchStoryState(storyKey, { cost_usd: tokenAgg.cost }).catch((err) => logger$26.warn({
|
|
13922
13311
|
err,
|
|
13923
13312
|
storyKey
|
|
13924
13313
|
}, "patchStoryState(cost_usd) failed — pipeline continues"));
|
|
@@ -13957,7 +13346,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
13957
13346
|
rationale: `Story ${storyKey} completed with result=${result} in ${wallClockSeconds}s. Tokens: ${tokenAgg.input}+${tokenAgg.output}. Review cycles: ${reviewCycles}.`
|
|
13958
13347
|
});
|
|
13959
13348
|
} catch (decisionErr) {
|
|
13960
|
-
logger$
|
|
13349
|
+
logger$26.warn({
|
|
13961
13350
|
err: decisionErr,
|
|
13962
13351
|
storyKey
|
|
13963
13352
|
}, "Failed to write story-metrics decision (best-effort)");
|
|
@@ -14036,7 +13425,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14036
13425
|
const LOW_OUTPUT_TOKEN_THRESHOLD = 100;
|
|
14037
13426
|
const unverified = tokenAgg.output < LOW_OUTPUT_TOKEN_THRESHOLD;
|
|
14038
13427
|
if (unverified) {
|
|
14039
|
-
logger$
|
|
13428
|
+
logger$26.warn({
|
|
14040
13429
|
storyKey,
|
|
14041
13430
|
outputTokens: tokenAgg.output,
|
|
14042
13431
|
threshold: LOW_OUTPUT_TOKEN_THRESHOLD
|
|
@@ -14060,13 +13449,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14060
13449
|
...unverified ? { unverified: true } : {}
|
|
14061
13450
|
});
|
|
14062
13451
|
} catch (emitErr) {
|
|
14063
|
-
logger$
|
|
13452
|
+
logger$26.warn({
|
|
14064
13453
|
err: emitErr,
|
|
14065
13454
|
storyKey
|
|
14066
13455
|
}, "Failed to emit story:metrics event (best-effort)");
|
|
14067
13456
|
}
|
|
14068
13457
|
} catch (err) {
|
|
14069
|
-
logger$
|
|
13458
|
+
logger$26.warn({
|
|
14070
13459
|
err,
|
|
14071
13460
|
storyKey
|
|
14072
13461
|
}, "Failed to write story metrics (best-effort)");
|
|
@@ -14095,7 +13484,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14095
13484
|
rationale: `Story ${storyKey} ${outcome} after ${reviewCycles} review cycle(s).`
|
|
14096
13485
|
});
|
|
14097
13486
|
} catch (err) {
|
|
14098
|
-
logger$
|
|
13487
|
+
logger$26.warn({
|
|
14099
13488
|
err,
|
|
14100
13489
|
storyKey
|
|
14101
13490
|
}, "Failed to write story-outcome decision (best-effort)");
|
|
@@ -14110,15 +13499,15 @@ function createImplementationOrchestrator(deps) {
|
|
|
14110
13499
|
if (escalationWorktree !== void 0) {
|
|
14111
13500
|
const cp = await checkpointStoryWorktree(payload.storyKey, `escalation: ${payload.escalationReason ?? payload.lastVerdict}`, escalationWorktree);
|
|
14112
13501
|
if (cp.status === "committed") {
|
|
14113
|
-
logger$
|
|
13502
|
+
logger$26.info({
|
|
14114
13503
|
storyKey: payload.storyKey,
|
|
14115
13504
|
sha: cp.sha
|
|
14116
13505
|
}, "escalation checkpoint: uncommitted worktree state preserved on story branch");
|
|
14117
|
-
if (runManifest !== null && cp.sha) runManifest.patchStoryState(payload.storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$
|
|
13506
|
+
if (runManifest !== null && cp.sha) runManifest.patchStoryState(payload.storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$26.warn({
|
|
14118
13507
|
err,
|
|
14119
13508
|
storyKey: payload.storyKey
|
|
14120
13509
|
}, "patchStoryState(checkpoint_sha, escalation) failed — pipeline continues"));
|
|
14121
|
-
} else if (cp.status === "failed") logger$
|
|
13510
|
+
} else if (cp.status === "failed") logger$26.warn({
|
|
14122
13511
|
storyKey: payload.storyKey,
|
|
14123
13512
|
stderr: cp.stderr.slice(0, 500)
|
|
14124
13513
|
}, "escalation checkpoint failed — worktree state remains uncommitted (inspect before any cleanup)");
|
|
@@ -14132,7 +13521,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14132
13521
|
storyKey: payload.storyKey,
|
|
14133
13522
|
msg: leakMsg
|
|
14134
13523
|
});
|
|
14135
|
-
logger$
|
|
13524
|
+
logger$26.warn({
|
|
14136
13525
|
storyKey: payload.storyKey,
|
|
14137
13526
|
leakedFileCount: leakedFiles.length
|
|
14138
13527
|
}, "escalation parent-tree leak detected");
|
|
@@ -14149,7 +13538,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14149
13538
|
runManifest.patchStoryState(payload.storyKey, {
|
|
14150
13539
|
escalation_reason: escalationReason,
|
|
14151
13540
|
...escalationDetail !== void 0 ? { escalation_detail: escalationDetail } : {}
|
|
14152
|
-
}).catch((err) => logger$
|
|
13541
|
+
}).catch((err) => logger$26.warn({
|
|
14153
13542
|
err,
|
|
14154
13543
|
storyKey: payload.storyKey
|
|
14155
13544
|
}, "patchStoryState(escalation_reason/detail) failed — pipeline continues"));
|
|
@@ -14176,7 +13565,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14176
13565
|
rationale: `Escalation diagnosis for ${payload.storyKey}: ${diagnosis.recommendedAction} — ${diagnosis.rationale}`
|
|
14177
13566
|
});
|
|
14178
13567
|
} catch (err) {
|
|
14179
|
-
logger$
|
|
13568
|
+
logger$26.warn({
|
|
14180
13569
|
err,
|
|
14181
13570
|
storyKey: payload.storyKey
|
|
14182
13571
|
}, "Failed to persist escalation diagnosis (best-effort)");
|
|
@@ -14225,7 +13614,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14225
13614
|
...updates
|
|
14226
13615
|
};
|
|
14227
13616
|
const opts = targetStatus === "complete" || targetStatus === "escalated" ? { completedAt: fullUpdated.completedAt } : void 0;
|
|
14228
|
-
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$
|
|
13617
|
+
wgRepo.updateStoryStatus(storyKey, targetStatus, opts).catch((err) => logger$26.warn({
|
|
14229
13618
|
err,
|
|
14230
13619
|
storyKey
|
|
14231
13620
|
}, "wg_stories status update failed (best-effort)"));
|
|
@@ -14241,7 +13630,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14241
13630
|
status: "dispatched",
|
|
14242
13631
|
phase: String(updates.phase),
|
|
14243
13632
|
started_at: fullUpdated.startedAt ?? new Date().toISOString()
|
|
14244
|
-
}).catch((err) => logger$
|
|
13633
|
+
}).catch((err) => logger$26.warn({
|
|
14245
13634
|
err,
|
|
14246
13635
|
storyKey
|
|
14247
13636
|
}, "patchStoryState(dispatched) failed — pipeline continues"));
|
|
@@ -14253,13 +13642,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14253
13642
|
completed_at: fullUpdated.completedAt ?? new Date().toISOString(),
|
|
14254
13643
|
review_cycles: fullUpdated.reviewCycles ?? 0,
|
|
14255
13644
|
dispatches: _storyDispatches.get(storyKey) ?? 0
|
|
14256
|
-
}).catch((err) => logger$
|
|
13645
|
+
}).catch((err) => logger$26.warn({
|
|
14257
13646
|
err,
|
|
14258
13647
|
storyKey
|
|
14259
13648
|
}, `patchStoryState(${manifestStatus}) failed — pipeline continues`));
|
|
14260
13649
|
} else {
|
|
14261
13650
|
const intermediatePhase = updates.phase;
|
|
14262
|
-
runManifest.patchStoryState(storyKey, { phase: String(intermediatePhase) }).catch((err) => logger$
|
|
13651
|
+
runManifest.patchStoryState(storyKey, { phase: String(intermediatePhase) }).catch((err) => logger$26.warn({
|
|
14263
13652
|
err,
|
|
14264
13653
|
storyKey,
|
|
14265
13654
|
phase: intermediatePhase
|
|
@@ -14278,13 +13667,17 @@ function createImplementationOrchestrator(deps) {
|
|
|
14278
13667
|
token_usage_json: serialized
|
|
14279
13668
|
});
|
|
14280
13669
|
} catch (err) {
|
|
14281
|
-
logger$
|
|
13670
|
+
logger$26.warn({ err }, "Failed to persist orchestrator state");
|
|
14282
13671
|
}
|
|
14283
13672
|
}
|
|
14284
13673
|
function recordProgress() {
|
|
14285
13674
|
_lastProgressTs = Date.now();
|
|
14286
13675
|
_stalledStories.clear();
|
|
14287
13676
|
}
|
|
13677
|
+
function resolveAcceptanceMode() {
|
|
13678
|
+
const configured = config.acceptanceMode ?? "advisory";
|
|
13679
|
+
return projectRoot !== void 0 ? effectiveAcceptanceMode(configured, projectRoot) : configured;
|
|
13680
|
+
}
|
|
14288
13681
|
const _journeyVerdicts = new Map();
|
|
14289
13682
|
/** External artifacts base: ~/.substrate/acceptance/<name>-<hash8>/<run>/ (H4.2 symmetry). */
|
|
14290
13683
|
function acceptanceArtifactsBase() {
|
|
@@ -14294,15 +13687,15 @@ function createImplementationOrchestrator(deps) {
|
|
|
14294
13687
|
}
|
|
14295
13688
|
async function runAcceptanceStage(storyKey, worktreeDir) {
|
|
14296
13689
|
const outcomes = [];
|
|
14297
|
-
const mode =
|
|
13690
|
+
const mode = resolveAcceptanceMode();
|
|
14298
13691
|
if (mode === "off" || projectRoot === void 0) return outcomes;
|
|
14299
13692
|
const journeyIds = _stories.get(storyKey)?.journeys ?? [];
|
|
14300
13693
|
if (journeyIds.length === 0) return outcomes;
|
|
14301
|
-
const registryLoad = await loadJourneyRegistryFromTrustedTree(projectRoot);
|
|
13694
|
+
const registryLoad = await loadJourneyRegistryFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
|
|
14302
13695
|
if (registryLoad.status !== "ok") return outcomes;
|
|
14303
|
-
const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot);
|
|
13696
|
+
const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
|
|
14304
13697
|
if (contractLoad.status !== "ok") {
|
|
14305
|
-
logger$
|
|
13698
|
+
logger$26.warn({
|
|
14306
13699
|
storyKey,
|
|
14307
13700
|
status: contractLoad.status
|
|
14308
13701
|
}, "A2.3: no usable acceptance contract — claimed journeys stay unwalked (acceptance-unrunnable at audit)");
|
|
@@ -14325,6 +13718,26 @@ function createImplementationOrchestrator(deps) {
|
|
|
14325
13718
|
outcomes.push(outcome);
|
|
14326
13719
|
const journeyDir = join$1(acceptanceArtifactsBase(), storyKey, journeyId);
|
|
14327
13720
|
const artifacts = [];
|
|
13721
|
+
{
|
|
13722
|
+
const changed = new Set(checkGitDiffFiles(worktreeDir).map((f$1) => f$1.replace(/\\/g, "/")));
|
|
13723
|
+
const renderTokens = new Set();
|
|
13724
|
+
for (const surface of journey.surfaces) {
|
|
13725
|
+
const def = contract.surfaces[surface];
|
|
13726
|
+
if (def !== void 0) for (const tok of def.render.trim().split(/\s+/)) renderTokens.add(tok.replace(/\\/g, "/"));
|
|
13727
|
+
}
|
|
13728
|
+
const gamedTargets = [...changed].filter((f$1) => renderTokens.has(f$1) || [...renderTokens].some((t) => t.endsWith("/" + f$1) || f$1.endsWith("/" + t)));
|
|
13729
|
+
if (gamedTargets.length > 0) {
|
|
13730
|
+
logger$26.warn({
|
|
13731
|
+
storyKey,
|
|
13732
|
+
journeyId,
|
|
13733
|
+
gamedTargets
|
|
13734
|
+
}, "acceptance-render-target-modified: the story modified file(s) the acceptance render command invokes — the rendered surface may reflect gamed output rather than real product behavior. Review the render targets; a canary (A6) is the structural check.");
|
|
13735
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
13736
|
+
storyKey,
|
|
13737
|
+
msg: `acceptance-render-target-modified (${journeyId}): story diff touches render target(s) ${gamedTargets.join(", ")} — verdict may reflect gamed output`
|
|
13738
|
+
});
|
|
13739
|
+
}
|
|
13740
|
+
}
|
|
14328
13741
|
let renderFailed = false;
|
|
14329
13742
|
for (const surface of journey.surfaces) {
|
|
14330
13743
|
if (surface === "web") continue;
|
|
@@ -14344,7 +13757,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14344
13757
|
});
|
|
14345
13758
|
if (res.status === "failed") {
|
|
14346
13759
|
renderFailed = true;
|
|
14347
|
-
logger$
|
|
13760
|
+
logger$26.warn({
|
|
14348
13761
|
storyKey,
|
|
14349
13762
|
journeyId,
|
|
14350
13763
|
surface,
|
|
@@ -14381,7 +13794,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14381
13794
|
storyKey,
|
|
14382
13795
|
journeyId
|
|
14383
13796
|
})
|
|
14384
|
-
})).catch((tokenErr) => logger$
|
|
13797
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
14385
13798
|
storyKey,
|
|
14386
13799
|
journeyId,
|
|
14387
13800
|
err: tokenErr
|
|
@@ -14400,7 +13813,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14400
13813
|
excerpt: v.evidence.excerpt
|
|
14401
13814
|
}))
|
|
14402
13815
|
});
|
|
14403
|
-
} else logger$
|
|
13816
|
+
} else logger$26.warn({
|
|
14404
13817
|
storyKey,
|
|
14405
13818
|
journeyId,
|
|
14406
13819
|
error: judge.error,
|
|
@@ -14410,25 +13823,25 @@ function createImplementationOrchestrator(deps) {
|
|
|
14410
13823
|
return outcomes;
|
|
14411
13824
|
}
|
|
14412
13825
|
async function auditJourneyCoverage(scope, opts) {
|
|
14413
|
-
const mode =
|
|
13826
|
+
const mode = resolveAcceptanceMode();
|
|
14414
13827
|
if (mode === "off" || projectRoot === void 0) return void 0;
|
|
14415
|
-
const registryLoad = await loadJourneyRegistryFromTrustedTree(projectRoot);
|
|
13828
|
+
const registryLoad = await loadJourneyRegistryFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
|
|
14416
13829
|
if (registryLoad.status === "absent") return void 0;
|
|
14417
13830
|
if (registryLoad.status === "invalid") return {
|
|
14418
13831
|
entries: [],
|
|
14419
13832
|
unrunnable: "journey registry is INVALID: " + registryLoad.issues.map((i) => `${i.path}: ${i.message}`).join("; ") + " — fix it (substrate acceptance validate) or the audit cannot run"
|
|
14420
13833
|
};
|
|
14421
13834
|
if (registryLoad.status !== "ok") {
|
|
14422
|
-
logger$
|
|
13835
|
+
logger$26.warn({ detail: registryLoad.message }, "A0.3: journey registry read failed — coverage audit skipped (environmental)");
|
|
14423
13836
|
return void 0;
|
|
14424
13837
|
}
|
|
14425
13838
|
let unrunnable;
|
|
14426
|
-
const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot);
|
|
13839
|
+
const contractLoad = await loadAcceptanceContractFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
|
|
14427
13840
|
if (contractLoad.status === "absent") unrunnable = `journey registry exists but the committed project profile has no acceptance: contract block (${ACCEPTANCE_CONTRACT_PROFILE_PATH}) — claimed journeys can never be walked. Declare render commands per surface.`;
|
|
14428
13841
|
else if (contractLoad.status === "invalid") unrunnable = "acceptance: contract block is INVALID: " + contractLoad.issues.map((i) => `${i.path}: ${i.message}`).join("; ");
|
|
14429
|
-
else if (contractLoad.status === "error") logger$
|
|
14430
|
-
const deferralsLoad = await loadJourneyDeferralsFromTrustedTree(projectRoot);
|
|
14431
|
-
if (deferralsLoad.status !== "ok") logger$
|
|
13842
|
+
else if (contractLoad.status === "error") logger$26.warn({ detail: contractLoad.message }, "A1.1: acceptance contract read failed (environmental) — treating as absent for this audit");
|
|
13843
|
+
const deferralsLoad = await loadJourneyDeferralsFromTrustedTree(projectRoot, _runStartSha ?? "HEAD");
|
|
13844
|
+
if (deferralsLoad.status !== "ok") logger$26.warn({ detail: deferralsLoad.status === "invalid" ? deferralsLoad.issues : deferralsLoad.message }, `A0.3: ${JOURNEY_DEFERRALS_PATH} unreadable/invalid — treating as no deferrals`);
|
|
14432
13845
|
const deferredJourneyIds = deferralsLoad.status === "ok" ? deferralsLoad.deferrals.map((d) => d.journey) : [];
|
|
14433
13846
|
const claims = [];
|
|
14434
13847
|
for (const [key, st] of _stories.entries()) for (const journeyId of st.journeys ?? []) claims.push({
|
|
@@ -14453,7 +13866,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14453
13866
|
entries,
|
|
14454
13867
|
summary: summarizeCoverage(entries)
|
|
14455
13868
|
});
|
|
14456
|
-
if (unrunnable !== void 0) logger$
|
|
13869
|
+
if (unrunnable !== void 0) logger$26.warn({ scope: scopeLabel }, `A1.1: acceptance gate unrunnable — ${unrunnable}`);
|
|
14457
13870
|
if (opts?.persist === true) {
|
|
14458
13871
|
const entriesWithVerdicts = entries.map((e) => {
|
|
14459
13872
|
const vs = _journeyVerdicts.get(e.journeyId);
|
|
@@ -14485,13 +13898,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
14485
13898
|
mkdirSync(dirname$1(reportPath), { recursive: true });
|
|
14486
13899
|
writeFileSync(reportPath, html, "utf-8");
|
|
14487
13900
|
} catch (err) {
|
|
14488
|
-
logger$
|
|
13901
|
+
logger$26.warn({ err }, "A2.2: verdict artifact write failed (best-effort)");
|
|
14489
13902
|
reportPath = void 0;
|
|
14490
13903
|
}
|
|
14491
13904
|
if (runManifest !== null) await runManifest.update({
|
|
14492
13905
|
journeys: entriesWithVerdicts,
|
|
14493
13906
|
...reportPath !== void 0 ? { acceptance_report_path: reportPath } : {}
|
|
14494
|
-
}).catch((err) => logger$
|
|
13907
|
+
}).catch((err) => logger$26.warn({ err }, "A0.3: manifest journeys ledger write failed — pipeline continues"));
|
|
14495
13908
|
}
|
|
14496
13909
|
return unrunnable !== void 0 ? {
|
|
14497
13910
|
entries,
|
|
@@ -14539,7 +13952,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14539
13952
|
...Object.keys(perStoryState).length > 0 ? { perStoryState } : {}
|
|
14540
13953
|
});
|
|
14541
13954
|
if (config.pipelineRunId !== void 0) updatePipelineRun(db, config.pipelineRunId, { current_phase: "implementation" }).catch((err) => {
|
|
14542
|
-
logger$
|
|
13955
|
+
logger$26.debug({ err }, "Heartbeat: failed to touch updated_at (non-fatal)");
|
|
14543
13956
|
});
|
|
14544
13957
|
const elapsed = Date.now() - _lastProgressTs;
|
|
14545
13958
|
let childPids = [];
|
|
@@ -14561,7 +13974,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14561
13974
|
}
|
|
14562
13975
|
if (childActive) {
|
|
14563
13976
|
_lastProgressTs = Date.now();
|
|
14564
|
-
logger$
|
|
13977
|
+
logger$26.debug({
|
|
14565
13978
|
storyKey: key,
|
|
14566
13979
|
phase: s$1.phase,
|
|
14567
13980
|
childPids
|
|
@@ -14570,7 +13983,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14570
13983
|
}
|
|
14571
13984
|
_stalledStories.add(key);
|
|
14572
13985
|
_storiesWithStall.add(key);
|
|
14573
|
-
logger$
|
|
13986
|
+
logger$26.warn({
|
|
14574
13987
|
storyKey: key,
|
|
14575
13988
|
phase: s$1.phase,
|
|
14576
13989
|
elapsedMs: elapsed,
|
|
@@ -14615,7 +14028,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14615
14028
|
for (let attempt = 0; attempt < MEMORY_PRESSURE_BACKOFF_MS.length; attempt++) {
|
|
14616
14029
|
const memState = dispatcher.getMemoryState();
|
|
14617
14030
|
if (!memState.isPressured) return true;
|
|
14618
|
-
logger$
|
|
14031
|
+
logger$26.warn({
|
|
14619
14032
|
storyKey,
|
|
14620
14033
|
freeMB: memState.freeMB,
|
|
14621
14034
|
thresholdMB: memState.thresholdMB,
|
|
@@ -14635,12 +14048,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14635
14048
|
* exhausted retries the story is ESCALATED.
|
|
14636
14049
|
*/
|
|
14637
14050
|
async function processStory(storyKey, storyOptions) {
|
|
14638
|
-
logger$
|
|
14051
|
+
logger$26.info({ storyKey }, "Processing story");
|
|
14639
14052
|
await initRetryCount(storyKey);
|
|
14640
14053
|
{
|
|
14641
14054
|
const memoryOk = await checkMemoryPressure(storyKey);
|
|
14642
14055
|
if (!memoryOk) {
|
|
14643
|
-
logger$
|
|
14056
|
+
logger$26.warn({ storyKey }, "Memory pressure exhausted — escalating story without dispatch");
|
|
14644
14057
|
const memPressureState = {
|
|
14645
14058
|
phase: "ESCALATED",
|
|
14646
14059
|
reviewCycles: 0,
|
|
@@ -14684,7 +14097,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14684
14097
|
if (match$2) {
|
|
14685
14098
|
const candidatePath = join$1(artifactsDir, match$2);
|
|
14686
14099
|
const validation = await isValidStoryFile(candidatePath);
|
|
14687
|
-
if (!validation.valid) logger$
|
|
14100
|
+
if (!validation.valid) logger$26.warn({
|
|
14688
14101
|
storyKey,
|
|
14689
14102
|
storyFilePath: candidatePath,
|
|
14690
14103
|
reason: validation.reason
|
|
@@ -14709,7 +14122,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14709
14122
|
storedHash,
|
|
14710
14123
|
currentHash
|
|
14711
14124
|
});
|
|
14712
|
-
logger$
|
|
14125
|
+
logger$26.info({
|
|
14713
14126
|
storyKey,
|
|
14714
14127
|
storedHash,
|
|
14715
14128
|
currentHash
|
|
@@ -14720,7 +14133,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14720
14133
|
} catch {}
|
|
14721
14134
|
if (!isDrift) {
|
|
14722
14135
|
storyFilePath = candidatePath;
|
|
14723
|
-
logger$
|
|
14136
|
+
logger$26.info({
|
|
14724
14137
|
storyKey,
|
|
14725
14138
|
storyFilePath
|
|
14726
14139
|
}, "Found existing story file — skipping create-story");
|
|
@@ -14745,12 +14158,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
14745
14158
|
const staleName = match$2.replace(/\.md$/, `.stale-${ts}.md`);
|
|
14746
14159
|
const stalePath = join$1(artifactsDir, staleName);
|
|
14747
14160
|
renameSync(candidatePath, stalePath);
|
|
14748
|
-
logger$
|
|
14161
|
+
logger$26.info({
|
|
14749
14162
|
storyKey,
|
|
14750
14163
|
staleName
|
|
14751
14164
|
}, `[orchestrator] story ${storyKey}: renamed drifted artifact to ${staleName} before re-dispatch`);
|
|
14752
14165
|
} catch (renameErr) {
|
|
14753
|
-
logger$
|
|
14166
|
+
logger$26.warn({
|
|
14754
14167
|
storyKey,
|
|
14755
14168
|
err: renameErr
|
|
14756
14169
|
}, "Failed to rename stale artifact before create-story re-dispatch; relying on 58-9d fraud-guard");
|
|
@@ -14759,7 +14172,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14759
14172
|
}
|
|
14760
14173
|
} catch {}
|
|
14761
14174
|
if (storyFilePath === void 0 && effectiveProjectRoot && isImplicitlyCovered(storyKey, effectiveProjectRoot)) {
|
|
14762
|
-
logger$
|
|
14175
|
+
logger$26.info({ storyKey }, `Story ${storyKey} appears implicitly covered — all expected new files already exist. Skipping create-story.`);
|
|
14763
14176
|
endPhase(storyKey, "create-story");
|
|
14764
14177
|
eventBus.emit("orchestrator:story-phase-complete", {
|
|
14765
14178
|
storyKey,
|
|
@@ -14814,7 +14227,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14814
14227
|
output_tokens: createResult.tokenUsage.output,
|
|
14815
14228
|
cost_usd: estimateDispatchCost(createResult.tokenUsage.input, createResult.tokenUsage.output),
|
|
14816
14229
|
metadata: JSON.stringify({ storyKey })
|
|
14817
|
-
})).catch((tokenErr) => logger$
|
|
14230
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
14818
14231
|
storyKey,
|
|
14819
14232
|
err: tokenErr
|
|
14820
14233
|
}, "Failed to record create-story token usage"));
|
|
@@ -14822,7 +14235,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14822
14235
|
if (createResult.result === "failed") {
|
|
14823
14236
|
const errMsg = createResult.error ?? "create-story failed";
|
|
14824
14237
|
const stderrSnippet = errMsg.includes("--- stderr ---") ? errMsg.slice(errMsg.indexOf("--- stderr ---") + 15, errMsg.indexOf("--- stderr ---") + 515) : errMsg.slice(0, 500);
|
|
14825
|
-
logger$
|
|
14238
|
+
logger$26.error({
|
|
14826
14239
|
storyKey,
|
|
14827
14240
|
stderrSnippet
|
|
14828
14241
|
}, `Create-story failed: ${stderrSnippet.split("\n")[0]}`);
|
|
@@ -14893,7 +14306,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14893
14306
|
const outsideWorktree = relToWorktree.startsWith("..") || isAbsolute(relToWorktree);
|
|
14894
14307
|
if (outsideWorktree) {
|
|
14895
14308
|
const errMsg = `create-story wrote its artifact OUTSIDE the story worktree: ${createResult.story_file} (resolved: ${resolvedStoryFile}) (worktree: ${effectiveProjectRoot}). The agent escaped its working directory — this is the parent/home-directory write-leak class (field finding #15). The stray file was NOT adopted; inspect and remove it.`;
|
|
14896
|
-
logger$
|
|
14309
|
+
logger$26.error({
|
|
14897
14310
|
storyKey,
|
|
14898
14311
|
storyFile: createResult.story_file,
|
|
14899
14312
|
worktree: effectiveProjectRoot
|
|
@@ -14921,7 +14334,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14921
14334
|
let claimedPath = createResult.story_file;
|
|
14922
14335
|
if (claimedPath.startsWith(escapedExpectedDir)) {
|
|
14923
14336
|
claimedPath = claimedPath.replace("/\\_bmad-output/", "/_bmad-output/");
|
|
14924
|
-
logger$
|
|
14337
|
+
logger$26.warn({
|
|
14925
14338
|
storyKey,
|
|
14926
14339
|
originalClaim: createResult.story_file,
|
|
14927
14340
|
normalizedClaim: claimedPath
|
|
@@ -14939,7 +14352,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14939
14352
|
if (escapedVariant !== claimedPath && existsSync(escapedVariant)) try {
|
|
14940
14353
|
renameSync(escapedVariant, claimedPath);
|
|
14941
14354
|
actualPath = claimedPath;
|
|
14942
|
-
logger$
|
|
14355
|
+
logger$26.warn({
|
|
14943
14356
|
storyKey,
|
|
14944
14357
|
escapedVariant,
|
|
14945
14358
|
canonicalPath: claimedPath
|
|
@@ -14950,7 +14363,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14950
14363
|
});
|
|
14951
14364
|
} catch (renameErr) {
|
|
14952
14365
|
actualPath = escapedVariant;
|
|
14953
|
-
logger$
|
|
14366
|
+
logger$26.warn({
|
|
14954
14367
|
storyKey,
|
|
14955
14368
|
escapedVariant,
|
|
14956
14369
|
canonicalPath: claimedPath,
|
|
@@ -14965,7 +14378,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14965
14378
|
if (actualPath === null) {
|
|
14966
14379
|
const outputTokens = createResult.tokenUsage?.output ?? 0;
|
|
14967
14380
|
const errMsg = `create-story claimed success (story_file: ${createResult.story_file}) but the file does not exist on disk (output tokens: ${outputTokens})`;
|
|
14968
|
-
logger$
|
|
14381
|
+
logger$26.error({
|
|
14969
14382
|
storyKey,
|
|
14970
14383
|
claimedPath: createResult.story_file,
|
|
14971
14384
|
outputTokens
|
|
@@ -14993,7 +14406,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
14993
14406
|
const mtimeISO = new Date(claimedStat.mtimeMs).toISOString();
|
|
14994
14407
|
const dispatchStartISO = new Date(dispatchStartMs).toISOString();
|
|
14995
14408
|
const errMsg = `create-story claimed success but did not rewrite ${actualPath} during this dispatch (file mtime ${mtimeISO} predates dispatch start ${dispatchStartISO}; output tokens: ${outputTokens})`;
|
|
14996
|
-
logger$
|
|
14409
|
+
logger$26.error({
|
|
14997
14410
|
storyKey,
|
|
14998
14411
|
claimedPath: actualPath,
|
|
14999
14412
|
mtimeISO,
|
|
@@ -15016,7 +14429,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15016
14429
|
return;
|
|
15017
14430
|
}
|
|
15018
14431
|
} catch (verifyErr) {
|
|
15019
|
-
logger$
|
|
14432
|
+
logger$26.warn({
|
|
15020
14433
|
storyKey,
|
|
15021
14434
|
err: verifyErr
|
|
15022
14435
|
}, "create-story post-dispatch file verification threw; proceeding with claimed path");
|
|
@@ -15025,7 +14438,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15025
14438
|
storyFilePath = createResult.story_file;
|
|
15026
14439
|
if (createResult.journeys !== void 0 && createResult.journeys.length > 0) {
|
|
15027
14440
|
updateStory(storyKey, { journeys: createResult.journeys });
|
|
15028
|
-
if (runManifest !== null) runManifest.patchStoryState(storyKey, { journeys: createResult.journeys }).catch((err) => logger$
|
|
14441
|
+
if (runManifest !== null) runManifest.patchStoryState(storyKey, { journeys: createResult.journeys }).catch((err) => logger$26.warn({
|
|
15029
14442
|
err,
|
|
15030
14443
|
storyKey
|
|
15031
14444
|
}, "A0.3: patchStoryState(journeys) failed — pipeline continues"));
|
|
@@ -15047,7 +14460,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15047
14460
|
const overlap = computeTitleOverlap(expectedTitle, createResult.story_title);
|
|
15048
14461
|
if (overlap < TITLE_OVERLAP_WARNING_THRESHOLD) {
|
|
15049
14462
|
const msg = `Story title mismatch: expected "${expectedTitle}" but got "${createResult.story_title}" (word overlap: ${Math.round(overlap * 100)}%). This may indicate the create-story agent received truncated context.`;
|
|
15050
|
-
logger$
|
|
14463
|
+
logger$26.warn({
|
|
15051
14464
|
storyKey,
|
|
15052
14465
|
expectedTitle,
|
|
15053
14466
|
generatedTitle: createResult.story_title,
|
|
@@ -15057,7 +14470,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15057
14470
|
storyKey,
|
|
15058
14471
|
msg
|
|
15059
14472
|
});
|
|
15060
|
-
} else logger$
|
|
14473
|
+
} else logger$26.debug({
|
|
15061
14474
|
storyKey,
|
|
15062
14475
|
expectedTitle,
|
|
15063
14476
|
generatedTitle: createResult.story_title,
|
|
@@ -15066,7 +14479,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15066
14479
|
}
|
|
15067
14480
|
}
|
|
15068
14481
|
} catch (titleValidationErr) {
|
|
15069
|
-
logger$
|
|
14482
|
+
logger$26.debug({
|
|
15070
14483
|
storyKey,
|
|
15071
14484
|
err: titleValidationErr
|
|
15072
14485
|
}, "Story title validation skipped due to error");
|
|
@@ -15107,7 +14520,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15107
14520
|
const pathDrift = pathFidelity?.drift ?? 0;
|
|
15108
14521
|
const clauseDrift = clauseFidelity.drift;
|
|
15109
14522
|
const overallDrift = Math.max(pathDrift, clauseDrift);
|
|
15110
|
-
logger$
|
|
14523
|
+
logger$26.debug({
|
|
15111
14524
|
storyKey,
|
|
15112
14525
|
pathDrift,
|
|
15113
14526
|
clauseDrift,
|
|
@@ -15129,7 +14542,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15129
14542
|
if (pathMissing.length > 0) reasons.push(`${pathMissing.length} named path(s) missing`);
|
|
15130
14543
|
if (numericMismatches.length > 0) reasons.push(`${numericMismatches.length} numeric quantifier mismatch(es) (e.g., "${numericMismatches[0].noun}" source=${numericMismatches[0].sourceCount} rendered=${numericMismatches[0].renderedCount})`);
|
|
15131
14544
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall (rendered ${clauseFidelity.renderedClauseCount}/${clauseFidelity.sourceClauseCount} = ${Math.round(clauseFidelity.clauseRatio * 100)}%)`);
|
|
15132
|
-
logger$
|
|
14545
|
+
logger$26.warn({
|
|
15133
14546
|
storyKey,
|
|
15134
14547
|
pathDrift,
|
|
15135
14548
|
clauseDrift,
|
|
@@ -15172,7 +14585,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15172
14585
|
storyFilePath = void 0;
|
|
15173
14586
|
continue;
|
|
15174
14587
|
} catch (renameErr) {
|
|
15175
|
-
logger$
|
|
14588
|
+
logger$26.warn({
|
|
15176
14589
|
storyKey,
|
|
15177
14590
|
err: renameErr,
|
|
15178
14591
|
stalePath
|
|
@@ -15186,7 +14599,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15186
14599
|
if (numericMismatches.length > 0) reasons.push(`numeric mismatches: ${numericMismatches.map((m) => `${m.noun} (source=${m.sourceCount}, rendered=${m.renderedCount})`).join("; ")}`);
|
|
15187
14600
|
if (clauseFidelity.clauseRatio < .7) reasons.push(`clause shortfall: source=${clauseFidelity.sourceClauseCount}, rendered=${clauseFidelity.renderedClauseCount}`);
|
|
15188
14601
|
const errMsg = `create-story output drifted from source AC after ${MAX_FIDELITY_RETRIES} retries; ` + reasons.join("; ");
|
|
15189
|
-
logger$
|
|
14602
|
+
logger$26.error({
|
|
15190
14603
|
storyKey,
|
|
15191
14604
|
pathDrift,
|
|
15192
14605
|
clauseDrift,
|
|
@@ -15213,7 +14626,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15213
14626
|
}
|
|
15214
14627
|
}
|
|
15215
14628
|
} catch (fidelityErr) {
|
|
15216
|
-
logger$
|
|
14629
|
+
logger$26.warn({
|
|
15217
14630
|
storyKey,
|
|
15218
14631
|
err: fidelityErr
|
|
15219
14632
|
}, "fidelity gate threw; proceeding without retry");
|
|
@@ -15225,7 +14638,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15225
14638
|
probeRetries++;
|
|
15226
14639
|
const stalePath = storyFilePath.replace(/\.md$/, `.stale-probe-${Date.now()}.md`);
|
|
15227
14640
|
renameSync(storyFilePath, stalePath);
|
|
15228
|
-
logger$
|
|
14641
|
+
logger$26.warn({
|
|
15229
14642
|
storyKey,
|
|
15230
14643
|
error: probeParse.error,
|
|
15231
14644
|
retries: probeRetries,
|
|
@@ -15250,7 +14663,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15250
14663
|
continue;
|
|
15251
14664
|
}
|
|
15252
14665
|
} catch (probeGateErr) {
|
|
15253
|
-
logger$
|
|
14666
|
+
logger$26.warn({
|
|
15254
14667
|
storyKey,
|
|
15255
14668
|
err: probeGateErr
|
|
15256
14669
|
}, "probe-validity gate threw; proceeding without retry (verification backstop)");
|
|
@@ -15273,14 +14686,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
15273
14686
|
...contract.transport !== void 0 ? { transport: contract.transport } : {}
|
|
15274
14687
|
})
|
|
15275
14688
|
});
|
|
15276
|
-
logger$
|
|
14689
|
+
logger$26.info({
|
|
15277
14690
|
storyKey,
|
|
15278
14691
|
contractCount: contracts.length,
|
|
15279
14692
|
contracts
|
|
15280
14693
|
}, "Stored interface contract declarations");
|
|
15281
14694
|
}
|
|
15282
14695
|
} catch (err) {
|
|
15283
|
-
logger$
|
|
14696
|
+
logger$26.warn({
|
|
15284
14697
|
storyKey,
|
|
15285
14698
|
error: err instanceof Error ? err.message : String(err)
|
|
15286
14699
|
}, "Failed to parse interface contracts — continuing without contract declarations");
|
|
@@ -15298,7 +14711,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15298
14711
|
const isStateIntegrating = stateIntegratingEnabled && detectsStateIntegratingAC(probeAuthorEpicContent);
|
|
15299
14712
|
if (isEventDriven || isStateIntegrating) {
|
|
15300
14713
|
const triggerClass = isEventDriven && isStateIntegrating ? "both" : isStateIntegrating ? "state-integrating" : "event-driven";
|
|
15301
|
-
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { probe_author_triggered_by: triggerClass }).catch((err) => logger$
|
|
14714
|
+
if (runManifest !== null && runManifest !== void 0) runManifest.patchStoryState(storyKey, { probe_author_triggered_by: triggerClass }).catch((err) => logger$26.warn({
|
|
15302
14715
|
err,
|
|
15303
14716
|
storyKey
|
|
15304
14717
|
}, "patchStoryState(probe_author_triggered_by) failed — pipeline continues"));
|
|
@@ -15333,7 +14746,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15333
14746
|
});
|
|
15334
14747
|
}
|
|
15335
14748
|
});
|
|
15336
|
-
logger$
|
|
14749
|
+
logger$26.info({
|
|
15337
14750
|
storyKey,
|
|
15338
14751
|
result: probeAuthorResult.result,
|
|
15339
14752
|
probesAuthoredCount: probeAuthorResult.probesAuthoredCount
|
|
@@ -15345,14 +14758,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
15345
14758
|
output_tokens: probeAuthorResult.tokenUsage.output,
|
|
15346
14759
|
cost_usd: estimateDispatchCost(probeAuthorResult.tokenUsage.input, probeAuthorResult.tokenUsage.output),
|
|
15347
14760
|
metadata: JSON.stringify({ storyKey })
|
|
15348
|
-
})).catch((tokenErr) => logger$
|
|
14761
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
15349
14762
|
storyKey,
|
|
15350
14763
|
err: tokenErr
|
|
15351
14764
|
}, "Failed to record probe-author token usage"));
|
|
15352
|
-
} else logger$
|
|
15353
|
-
} else logger$
|
|
14765
|
+
} else logger$26.debug({ storyKey }, "probe-author: story artifact already has ## Runtime Probes — skipping gate");
|
|
14766
|
+
} else logger$26.debug({ storyKey }, "probe-author: source AC not event-driven — skipping gate");
|
|
15354
14767
|
} catch (probeAuthorErr) {
|
|
15355
|
-
logger$
|
|
14768
|
+
logger$26.warn({
|
|
15356
14769
|
storyKey,
|
|
15357
14770
|
err: probeAuthorErr
|
|
15358
14771
|
}, "probe-author gate threw unexpectedly; proceeding to test-plan without authored probes");
|
|
@@ -15382,10 +14795,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
15382
14795
|
});
|
|
15383
14796
|
testPlanPhaseResult = testPlanResult.result;
|
|
15384
14797
|
testPlanTokenUsage = testPlanResult.tokenUsage;
|
|
15385
|
-
if (testPlanResult.result === "success") logger$
|
|
15386
|
-
else logger$
|
|
14798
|
+
if (testPlanResult.result === "success") logger$26.info({ storyKey }, "Test plan generated successfully");
|
|
14799
|
+
else logger$26.warn({ storyKey }, "Test planning returned failed result — proceeding to dev-story without test plan");
|
|
15387
14800
|
} catch (err) {
|
|
15388
|
-
logger$
|
|
14801
|
+
logger$26.warn({
|
|
15389
14802
|
storyKey,
|
|
15390
14803
|
err
|
|
15391
14804
|
}, "Test planning failed — proceeding to dev-story without test plan");
|
|
@@ -15398,7 +14811,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15398
14811
|
output_tokens: testPlanTokenUsage.output,
|
|
15399
14812
|
cost_usd: estimateDispatchCost(testPlanTokenUsage.input, testPlanTokenUsage.output),
|
|
15400
14813
|
metadata: JSON.stringify({ storyKey })
|
|
15401
|
-
})).catch((tokenErr) => logger$
|
|
14814
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
15402
14815
|
storyKey,
|
|
15403
14816
|
err: tokenErr
|
|
15404
14817
|
}, "Failed to record test-plan token usage"));
|
|
@@ -15461,7 +14874,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15461
14874
|
]
|
|
15462
14875
|
}).trim();
|
|
15463
14876
|
} catch {}
|
|
15464
|
-
if (baselineHeadSha !== void 0 && runManifest !== null) runManifest.patchStoryState(storyKey, { baseline_sha: baselineHeadSha }).catch((err) => logger$
|
|
14877
|
+
if (baselineHeadSha !== void 0 && runManifest !== null) runManifest.patchStoryState(storyKey, { baseline_sha: baselineHeadSha }).catch((err) => logger$26.warn({
|
|
15465
14878
|
err,
|
|
15466
14879
|
storyKey
|
|
15467
14880
|
}, "patchStoryState(baseline_sha) failed — pipeline continues"));
|
|
@@ -15471,7 +14884,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15471
14884
|
storyContentForAnalysis = await readFile$1(storyFilePath ?? "", "utf-8");
|
|
15472
14885
|
storyContentForVerification = storyContentForAnalysis;
|
|
15473
14886
|
} catch (err) {
|
|
15474
|
-
logger$
|
|
14887
|
+
logger$26.error({
|
|
15475
14888
|
storyKey,
|
|
15476
14889
|
storyFilePath,
|
|
15477
14890
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -15479,7 +14892,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15479
14892
|
}
|
|
15480
14893
|
const analysis = analyzeStoryComplexity(storyContentForAnalysis);
|
|
15481
14894
|
const batches = planTaskBatches(analysis);
|
|
15482
|
-
logger$
|
|
14895
|
+
logger$26.info({
|
|
15483
14896
|
storyKey,
|
|
15484
14897
|
estimatedScope: analysis.estimatedScope,
|
|
15485
14898
|
batchCount: batches.length,
|
|
@@ -15497,7 +14910,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15497
14910
|
if (_state !== "RUNNING") break;
|
|
15498
14911
|
const taskScope = batch.taskIds.map((id, i) => `T${id}: ${batch.taskTitles[i] ?? ""}`).join("\n");
|
|
15499
14912
|
const priorFiles = allFilesModified.size > 0 ? Array.from(allFilesModified) : void 0;
|
|
15500
|
-
logger$
|
|
14913
|
+
logger$26.info({
|
|
15501
14914
|
storyKey,
|
|
15502
14915
|
batchIndex: batch.batchIndex,
|
|
15503
14916
|
taskCount: batch.taskIds.length
|
|
@@ -15529,7 +14942,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15529
14942
|
});
|
|
15530
14943
|
} catch (batchErr) {
|
|
15531
14944
|
const errMsg = batchErr instanceof Error ? batchErr.message : String(batchErr);
|
|
15532
|
-
logger$
|
|
14945
|
+
logger$26.warn({
|
|
15533
14946
|
storyKey,
|
|
15534
14947
|
batchIndex: batch.batchIndex,
|
|
15535
14948
|
error: errMsg
|
|
@@ -15551,7 +14964,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15551
14964
|
filesModified: batchFilesModified,
|
|
15552
14965
|
result: batchResult.result === "success" ? "success" : "failed"
|
|
15553
14966
|
};
|
|
15554
|
-
logger$
|
|
14967
|
+
logger$26.info(batchMetrics, "Batch dev-story metrics");
|
|
15555
14968
|
for (const f$1 of batchFilesModified) allFilesModified.add(f$1);
|
|
15556
14969
|
if (batchFilesModified.length > 0) batchFileGroups.push({
|
|
15557
14970
|
batchIndex: batch.batchIndex,
|
|
@@ -15570,13 +14983,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
15570
14983
|
durationMs: batchDurationMs,
|
|
15571
14984
|
result: batchMetrics.result
|
|
15572
14985
|
})
|
|
15573
|
-
})).catch((tokenErr) => logger$
|
|
14986
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
15574
14987
|
storyKey,
|
|
15575
14988
|
batchIndex: batch.batchIndex,
|
|
15576
14989
|
err: tokenErr
|
|
15577
14990
|
}, "Failed to record batch token usage"));
|
|
15578
14991
|
if (batchResult.tokenUsage?.output !== void 0) devOutputTokenCount = (devOutputTokenCount ?? 0) + batchResult.tokenUsage.output;
|
|
15579
|
-
if (batchResult.result === "failed") logger$
|
|
14992
|
+
if (batchResult.result === "failed") logger$26.warn({
|
|
15580
14993
|
storyKey,
|
|
15581
14994
|
batchIndex: batch.batchIndex,
|
|
15582
14995
|
error: batchResult.error
|
|
@@ -15621,7 +15034,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15621
15034
|
output_tokens: devResult.tokenUsage.output,
|
|
15622
15035
|
cost_usd: estimateDispatchCost(devResult.tokenUsage.input, devResult.tokenUsage.output),
|
|
15623
15036
|
metadata: JSON.stringify({ storyKey })
|
|
15624
|
-
})).catch((tokenErr) => logger$
|
|
15037
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
15625
15038
|
storyKey,
|
|
15626
15039
|
err: tokenErr
|
|
15627
15040
|
}, "Failed to record dev-story token usage"));
|
|
@@ -15636,7 +15049,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15636
15049
|
endPhase(storyKey, "dev-story", devStoryModel);
|
|
15637
15050
|
const timeoutFiles = checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
15638
15051
|
if (timeoutFiles.length === 0) {
|
|
15639
|
-
logger$
|
|
15052
|
+
logger$26.warn({ storyKey }, "Dev-story timeout with zero modified files — escalating immediately (no checkpoint)");
|
|
15640
15053
|
updateStory(storyKey, {
|
|
15641
15054
|
phase: "ESCALATED",
|
|
15642
15055
|
error: "timeout-no-files",
|
|
@@ -15652,7 +15065,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15652
15065
|
await persistState();
|
|
15653
15066
|
return;
|
|
15654
15067
|
}
|
|
15655
|
-
logger$
|
|
15068
|
+
logger$26.info({
|
|
15656
15069
|
storyKey,
|
|
15657
15070
|
filesCount: timeoutFiles.length
|
|
15658
15071
|
}, "Dev-story timeout with partial files — capturing checkpoint");
|
|
@@ -15669,7 +15082,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15669
15082
|
]
|
|
15670
15083
|
}).trim();
|
|
15671
15084
|
} catch (diffErr) {
|
|
15672
|
-
logger$
|
|
15085
|
+
logger$26.warn({
|
|
15673
15086
|
storyKey,
|
|
15674
15087
|
error: diffErr instanceof Error ? diffErr.message : String(diffErr)
|
|
15675
15088
|
}, "Failed to capture git diff for checkpoint — proceeding with empty diff");
|
|
@@ -15743,9 +15156,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
15743
15156
|
checkpointRetryPrompt = assembled.prompt;
|
|
15744
15157
|
} catch {
|
|
15745
15158
|
checkpointRetryPrompt = `Continue story ${storyKey} from checkpoint. Your prior attempt timed out. Do not redo completed work.`;
|
|
15746
|
-
logger$
|
|
15159
|
+
logger$26.warn({ storyKey }, "Failed to assemble checkpoint retry prompt — using fallback");
|
|
15747
15160
|
}
|
|
15748
|
-
logger$
|
|
15161
|
+
logger$26.info({
|
|
15749
15162
|
storyKey,
|
|
15750
15163
|
filesCount: checkpointData.filesModified.length
|
|
15751
15164
|
}, "Dispatching checkpoint retry for timed-out story");
|
|
@@ -15775,7 +15188,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15775
15188
|
outcome: checkpointRetryResult.status === "timeout" ? "escalated" : "retried",
|
|
15776
15189
|
cost_usd: 0,
|
|
15777
15190
|
timestamp: new Date().toISOString()
|
|
15778
|
-
}).catch((err) => logger$
|
|
15191
|
+
}).catch((err) => logger$26.warn({
|
|
15779
15192
|
err,
|
|
15780
15193
|
storyKey
|
|
15781
15194
|
}, "appendRecoveryEntry(checkpoint-retry) failed — pipeline continues"));
|
|
@@ -15788,7 +15201,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15788
15201
|
} : void 0 }
|
|
15789
15202
|
});
|
|
15790
15203
|
if (checkpointRetryResult.status === "timeout") {
|
|
15791
|
-
logger$
|
|
15204
|
+
logger$26.warn({ storyKey }, "Checkpoint retry dispatch timed out — escalating story");
|
|
15792
15205
|
updateStory(storyKey, {
|
|
15793
15206
|
phase: "ESCALATED",
|
|
15794
15207
|
error: "checkpoint-retry-timeout",
|
|
@@ -15808,7 +15221,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15808
15221
|
replaceDevStorySignals(retryParsed);
|
|
15809
15222
|
devFilesModified = retryParsed?.files_modified ?? checkGitDiffFiles(effectiveProjectRoot ?? process.cwd());
|
|
15810
15223
|
if (checkpointRetryResult.status === "completed" && retryParsed?.result === "success") devStoryWasSuccess = true;
|
|
15811
|
-
else logger$
|
|
15224
|
+
else logger$26.warn({
|
|
15812
15225
|
storyKey,
|
|
15813
15226
|
status: checkpointRetryResult.status
|
|
15814
15227
|
}, "Checkpoint retry completed with failure — proceeding to code review");
|
|
@@ -15818,13 +15231,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
15818
15231
|
replaceDevStorySignals(devResult);
|
|
15819
15232
|
if (devResult.result === "success") devStoryWasSuccess = true;
|
|
15820
15233
|
else {
|
|
15821
|
-
logger$
|
|
15234
|
+
logger$26.warn({
|
|
15822
15235
|
storyKey,
|
|
15823
15236
|
error: devResult.error,
|
|
15824
15237
|
filesModified: devFilesModified.length
|
|
15825
15238
|
}, "Dev-story reported failure, proceeding to code review");
|
|
15826
15239
|
if (!devResult.error?.startsWith("dispatch_timeout")) {
|
|
15827
|
-
logger$
|
|
15240
|
+
logger$26.warn({
|
|
15828
15241
|
storyKey,
|
|
15829
15242
|
error: devResult.error
|
|
15830
15243
|
}, "Agent process failure (non-timeout) — story will proceed to code review with partial work");
|
|
@@ -15905,7 +15318,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15905
15318
|
}).trim();
|
|
15906
15319
|
if (committedFiles.length > 0) gitDiffFiles = committedFiles.split("\n").filter(Boolean);
|
|
15907
15320
|
} catch {}
|
|
15908
|
-
logger$
|
|
15321
|
+
logger$26.info({
|
|
15909
15322
|
storyKey,
|
|
15910
15323
|
baselineHeadSha,
|
|
15911
15324
|
committedFileCount: gitDiffFiles?.length ?? 0
|
|
@@ -15913,7 +15326,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15913
15326
|
} else {
|
|
15914
15327
|
const outsideWorktreeFiles = detectWorkOutsideWorktree(effectiveProjectRoot, projectRoot, checkGitDiffFiles);
|
|
15915
15328
|
const misrouted = outsideWorktreeFiles.length > 0;
|
|
15916
|
-
logger$
|
|
15329
|
+
logger$26.warn({
|
|
15917
15330
|
storyKey,
|
|
15918
15331
|
misrouteSuspected: misrouted,
|
|
15919
15332
|
outsideWorktreeFileCount: outsideWorktreeFiles.length
|
|
@@ -15989,7 +15402,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
15989
15402
|
}
|
|
15990
15403
|
}
|
|
15991
15404
|
if (implClassification.hasImplementation && implAddedLines === 0) {
|
|
15992
|
-
logger$
|
|
15405
|
+
logger$26.warn({
|
|
15993
15406
|
storyKey,
|
|
15994
15407
|
changed: gitDiffFiles.slice(0, 10)
|
|
15995
15408
|
}, "dev-story reported success but its implementation files added zero non-whitespace lines (empty stub / whitespace-only / pure deletion) — escalating no-implementation");
|
|
@@ -16011,7 +15424,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16011
15424
|
return;
|
|
16012
15425
|
}
|
|
16013
15426
|
if (!implClassification.hasImplementation) {
|
|
16014
|
-
logger$
|
|
15427
|
+
logger$26.warn({
|
|
16015
15428
|
storyKey,
|
|
16016
15429
|
artifactFiles: implClassification.artifactOnly.slice(0, 10)
|
|
16017
15430
|
}, "dev-story reported success but the diff contains only pipeline artifacts — no implementation was produced");
|
|
@@ -16040,24 +15453,24 @@ function createImplementationOrchestrator(deps) {
|
|
|
16040
15453
|
if (dirtyNow.length > 0) if (devStoryWasSuccess) {
|
|
16041
15454
|
const earlyCommit = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirtyNow, effectiveProjectRoot);
|
|
16042
15455
|
if (earlyCommit.status === "committed") {
|
|
16043
|
-
logger$
|
|
15456
|
+
logger$26.info({
|
|
16044
15457
|
storyKey,
|
|
16045
15458
|
sha: earlyCommit.sha,
|
|
16046
15459
|
fileCount: earlyCommit.filesStaged.length
|
|
16047
15460
|
}, "commit-first: dev-story output committed to story branch");
|
|
16048
|
-
if (runManifest !== null && earlyCommit.sha) runManifest.patchStoryState(storyKey, { commit_sha: earlyCommit.sha }).catch((err) => logger$
|
|
15461
|
+
if (runManifest !== null && earlyCommit.sha) runManifest.patchStoryState(storyKey, { commit_sha: earlyCommit.sha }).catch((err) => logger$26.warn({
|
|
16049
15462
|
err,
|
|
16050
15463
|
storyKey
|
|
16051
15464
|
}, "patchStoryState(commit_sha, commit-first) failed — pipeline continues"));
|
|
16052
15465
|
} else if (earlyCommit.status === "failed") {
|
|
16053
15466
|
_devOutputCommitHookFailure = earlyCommit.stderr;
|
|
16054
15467
|
const cp = await checkpointStoryWorktree(storyKey, "dev-story output (deliverable commit rejected by hooks)", effectiveProjectRoot);
|
|
16055
|
-
logger$
|
|
15468
|
+
logger$26.warn({
|
|
16056
15469
|
storyKey,
|
|
16057
15470
|
checkpoint: cp.status,
|
|
16058
15471
|
hookStderr: earlyCommit.stderr.slice(0, 500)
|
|
16059
15472
|
}, "commit-first: hooks rejected feat commit — work preserved as wip checkpoint");
|
|
16060
|
-
if (cp.status === "committed" && runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$
|
|
15473
|
+
if (cp.status === "committed" && runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$26.warn({
|
|
16061
15474
|
err,
|
|
16062
15475
|
storyKey
|
|
16063
15476
|
}, "patchStoryState(checkpoint_sha) failed — pipeline continues"));
|
|
@@ -16065,11 +15478,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
16065
15478
|
} else {
|
|
16066
15479
|
const cp = await checkpointStoryWorktree(storyKey, "dev-story partial output", effectiveProjectRoot);
|
|
16067
15480
|
if (cp.status === "committed") {
|
|
16068
|
-
logger$
|
|
15481
|
+
logger$26.info({
|
|
16069
15482
|
storyKey,
|
|
16070
15483
|
sha: cp.sha
|
|
16071
15484
|
}, "commit-first: partial dev-story output checkpointed");
|
|
16072
|
-
if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$
|
|
15485
|
+
if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$26.warn({
|
|
16073
15486
|
err,
|
|
16074
15487
|
storyKey
|
|
16075
15488
|
}, "patchStoryState(checkpoint_sha) failed — pipeline continues"));
|
|
@@ -16103,10 +15516,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
16103
15516
|
"pipe"
|
|
16104
15517
|
]
|
|
16105
15518
|
});
|
|
16106
|
-
logger$
|
|
15519
|
+
logger$26.info({ storyKey }, "Secondary typecheck (tsc --noEmit) passed");
|
|
16107
15520
|
} catch (tscErr) {
|
|
16108
15521
|
const tscOutput = tscErr instanceof Error && "stdout" in tscErr ? String(tscErr.stdout ?? "").slice(0, 2e3) : "";
|
|
16109
|
-
logger$
|
|
15522
|
+
logger$26.warn({
|
|
16110
15523
|
storyKey,
|
|
16111
15524
|
tscOutput
|
|
16112
15525
|
}, "Secondary typecheck (tsc --noEmit) failed — treating as build failure");
|
|
@@ -16121,7 +15534,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16121
15534
|
if (buildVerifyResult.status === "passed") {
|
|
16122
15535
|
_buildPassed = true;
|
|
16123
15536
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
16124
|
-
logger$
|
|
15537
|
+
logger$26.info({ storyKey }, "Build verification passed");
|
|
16125
15538
|
} else if (buildVerifyResult.status === "failed" || buildVerifyResult.status === "timeout") {
|
|
16126
15539
|
const truncatedOutput = (buildVerifyResult.output ?? "").slice(0, 2e3);
|
|
16127
15540
|
const reason = buildVerifyResult.reason ?? "build-verification-failed";
|
|
@@ -16130,7 +15543,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16130
15543
|
const resolvedRoot = effectiveProjectRoot ?? process.cwd();
|
|
16131
15544
|
const hasChanges = detectPackageChanges(_packageSnapshot, resolvedRoot);
|
|
16132
15545
|
if (hasChanges) {
|
|
16133
|
-
logger$
|
|
15546
|
+
logger$26.warn({ storyKey }, "Package files changed since snapshot — restoring to prevent cascade");
|
|
16134
15547
|
const restoreResult = restorePackageSnapshot(_packageSnapshot, { projectRoot: resolvedRoot });
|
|
16135
15548
|
if (restoreResult.restored) {
|
|
16136
15549
|
const retryAfterRestore = runBuildVerification({
|
|
@@ -16143,11 +15556,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
16143
15556
|
retryPassed = true;
|
|
16144
15557
|
_buildPassed = true;
|
|
16145
15558
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
16146
|
-
logger$
|
|
15559
|
+
logger$26.warn({
|
|
16147
15560
|
storyKey,
|
|
16148
15561
|
filesRestored: restoreResult.filesRestored
|
|
16149
15562
|
}, "Build passed after package snapshot restore — cross-story pollution detected and cleaned");
|
|
16150
|
-
} else logger$
|
|
15563
|
+
} else logger$26.warn({
|
|
16151
15564
|
storyKey,
|
|
16152
15565
|
filesRestored: restoreResult.filesRestored
|
|
16153
15566
|
}, "Build still fails after snapshot restore — story has its own build errors");
|
|
@@ -16159,7 +15572,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16159
15572
|
if (missingPkgMatch && buildVerifyResult.status !== "timeout") {
|
|
16160
15573
|
const missingPkg = missingPkgMatch[1].replace(/^(@[^/]+\/[^/]+)\/.*$/, "$1").replace(/^([^@][^/]*)\/.*$/, "$1");
|
|
16161
15574
|
const resolvedRoot = effectiveProjectRoot ?? process.cwd();
|
|
16162
|
-
logger$
|
|
15575
|
+
logger$26.warn({
|
|
16163
15576
|
storyKey,
|
|
16164
15577
|
missingPkg
|
|
16165
15578
|
}, "Build-fix retry: detected missing npm package — attempting npm install");
|
|
@@ -16170,7 +15583,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16170
15583
|
encoding: "utf-8",
|
|
16171
15584
|
stdio: "pipe"
|
|
16172
15585
|
});
|
|
16173
|
-
logger$
|
|
15586
|
+
logger$26.warn({
|
|
16174
15587
|
storyKey,
|
|
16175
15588
|
missingPkg
|
|
16176
15589
|
}, "Build-fix retry: npm install succeeded — retrying build verification");
|
|
@@ -16184,18 +15597,18 @@ function createImplementationOrchestrator(deps) {
|
|
|
16184
15597
|
retryPassed = true;
|
|
16185
15598
|
_buildPassed = true;
|
|
16186
15599
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
16187
|
-
logger$
|
|
15600
|
+
logger$26.warn({
|
|
16188
15601
|
storyKey,
|
|
16189
15602
|
missingPkg
|
|
16190
15603
|
}, "Build-fix retry: build verification passed after installing missing package");
|
|
16191
|
-
} else logger$
|
|
15604
|
+
} else logger$26.warn({
|
|
16192
15605
|
storyKey,
|
|
16193
15606
|
missingPkg,
|
|
16194
15607
|
retryStatus: retryResult.status
|
|
16195
15608
|
}, "Build-fix retry: build still fails after installing missing package — escalating");
|
|
16196
15609
|
} catch (installErr) {
|
|
16197
15610
|
const installMsg = installErr instanceof Error ? installErr.message : String(installErr);
|
|
16198
|
-
logger$
|
|
15611
|
+
logger$26.warn({
|
|
16199
15612
|
storyKey,
|
|
16200
15613
|
missingPkg,
|
|
16201
15614
|
error: installMsg
|
|
@@ -16205,7 +15618,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16205
15618
|
if (!retryPassed) {
|
|
16206
15619
|
let buildFixPassed = false;
|
|
16207
15620
|
if (buildVerifyResult.status === "failed" && storyFilePath !== void 0) try {
|
|
16208
|
-
logger$
|
|
15621
|
+
logger$26.info({ storyKey }, "Dispatching build-fix agent");
|
|
16209
15622
|
startPhase(storyKey, "build-fix");
|
|
16210
15623
|
const storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
16211
15624
|
let buildFixTemplate;
|
|
@@ -16242,11 +15655,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
16242
15655
|
buildFixPassed = true;
|
|
16243
15656
|
_buildPassed = true;
|
|
16244
15657
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
16245
|
-
logger$
|
|
16246
|
-
} else logger$
|
|
15658
|
+
logger$26.info({ storyKey }, "Build passed after build-fix dispatch");
|
|
15659
|
+
} else logger$26.warn({ storyKey }, "Build still fails after build-fix dispatch — escalating");
|
|
16247
15660
|
} catch (fixErr) {
|
|
16248
15661
|
const fixMsg = fixErr instanceof Error ? fixErr.message : String(fixErr);
|
|
16249
|
-
logger$
|
|
15662
|
+
logger$26.warn({
|
|
16250
15663
|
storyKey,
|
|
16251
15664
|
error: fixMsg
|
|
16252
15665
|
}, "Build-fix dispatch failed — escalating");
|
|
@@ -16283,7 +15696,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16283
15696
|
eventBus.emit("decision:halt-skipped-non-interactive", payload);
|
|
16284
15697
|
}
|
|
16285
15698
|
}).catch((err) => {
|
|
16286
|
-
logger$
|
|
15699
|
+
logger$26.warn({
|
|
16287
15700
|
err,
|
|
16288
15701
|
storyKey
|
|
16289
15702
|
}, "interactive prompt failed — continuing with default action");
|
|
@@ -16300,7 +15713,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16300
15713
|
exitCode: buildVerifyResult.exitCode ?? 1,
|
|
16301
15714
|
output: truncatedOutput
|
|
16302
15715
|
});
|
|
16303
|
-
logger$
|
|
15716
|
+
logger$26.warn({
|
|
16304
15717
|
storyKey,
|
|
16305
15718
|
reason,
|
|
16306
15719
|
exitCode: buildVerifyResult.exitCode,
|
|
@@ -16334,7 +15747,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16334
15747
|
storyKey
|
|
16335
15748
|
});
|
|
16336
15749
|
if (icResult.potentiallyAffectedTests.length > 0) {
|
|
16337
|
-
logger$
|
|
15750
|
+
logger$26.warn({
|
|
16338
15751
|
storyKey,
|
|
16339
15752
|
modifiedInterfaces: icResult.modifiedInterfaces,
|
|
16340
15753
|
potentiallyAffectedTests: icResult.potentiallyAffectedTests
|
|
@@ -16437,14 +15850,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
16437
15850
|
adapter: db,
|
|
16438
15851
|
engine: "linear"
|
|
16439
15852
|
}).catch((recoveryErr) => {
|
|
16440
|
-
logger$
|
|
15853
|
+
logger$26.warn({
|
|
16441
15854
|
storyKey,
|
|
16442
15855
|
err: recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr)
|
|
16443
15856
|
}, "Recovery Engine invocation failed — falling through to VERIFICATION_FAILED (best-effort)");
|
|
16444
15857
|
return null;
|
|
16445
15858
|
});
|
|
16446
15859
|
if (recoveryResult?.action === "halt-entire-run") {
|
|
16447
|
-
logger$
|
|
15860
|
+
logger$26.error({
|
|
16448
15861
|
storyKey,
|
|
16449
15862
|
pendingProposalsCount: recoveryResult.pendingProposalsCount
|
|
16450
15863
|
}, "Recovery Engine safety valve: halting entire run due to >= 5 pending proposals");
|
|
@@ -16456,13 +15869,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
16456
15869
|
outcome: "escalated",
|
|
16457
15870
|
cost_usd: 0,
|
|
16458
15871
|
timestamp: new Date().toISOString()
|
|
16459
|
-
}).catch((err) => logger$
|
|
15872
|
+
}).catch((err) => logger$26.warn({
|
|
16460
15873
|
err,
|
|
16461
15874
|
storyKey
|
|
16462
15875
|
}, "appendRecoveryEntry(halt-entire-run) failed — pipeline continues"));
|
|
16463
15876
|
_budgetExhausted = true;
|
|
16464
15877
|
} else if (recoveryResult?.action === "retry") {
|
|
16465
|
-
logger$
|
|
15878
|
+
logger$26.info({
|
|
16466
15879
|
storyKey,
|
|
16467
15880
|
attempt: recoveryResult.attempt,
|
|
16468
15881
|
retryBudgetRemaining: recoveryResult.retryBudgetRemaining
|
|
@@ -16514,22 +15927,22 @@ function createImplementationOrchestrator(deps) {
|
|
|
16514
15927
|
outcome: tierARecovered ? "recovered" : "retried",
|
|
16515
15928
|
cost_usd: 0,
|
|
16516
15929
|
timestamp: new Date().toISOString()
|
|
16517
|
-
}).catch((err) => logger$
|
|
15930
|
+
}).catch((err) => logger$26.warn({
|
|
16518
15931
|
err,
|
|
16519
15932
|
storyKey
|
|
16520
15933
|
}, "appendRecoveryEntry(tier-a) failed — pipeline continues"));
|
|
16521
15934
|
if (tierARecovered) {
|
|
16522
|
-
logger$
|
|
15935
|
+
logger$26.info({ storyKey }, "Recovery Engine Tier A retry succeeded — story proceeding to COMPLETE");
|
|
16523
15936
|
shouldFallThroughToComplete = true;
|
|
16524
|
-
} else logger$
|
|
15937
|
+
} else logger$26.warn({ storyKey }, "Recovery Engine Tier A retry still failed — falling through to VERIFICATION_FAILED");
|
|
16525
15938
|
} catch (retryErr) {
|
|
16526
|
-
logger$
|
|
15939
|
+
logger$26.warn({
|
|
16527
15940
|
storyKey,
|
|
16528
15941
|
err: retryErr instanceof Error ? retryErr.message : String(retryErr)
|
|
16529
15942
|
}, "Recovery Engine Tier A re-dispatch threw — falling through to VERIFICATION_FAILED");
|
|
16530
15943
|
}
|
|
16531
15944
|
} else if (recoveryResult?.action === "propose") {
|
|
16532
|
-
logger$
|
|
15945
|
+
logger$26.info({ storyKey }, "Recovery Engine Tier B: proposal appended — marking story ESCALATED for operator re-scope");
|
|
16533
15946
|
if (runManifest) runManifest.appendRecoveryEntry({
|
|
16534
15947
|
story_key: storyKey,
|
|
16535
15948
|
attempt_number: finalReviewCycles + 1,
|
|
@@ -16538,7 +15951,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16538
15951
|
outcome: "escalated",
|
|
16539
15952
|
cost_usd: 0,
|
|
16540
15953
|
timestamp: new Date().toISOString()
|
|
16541
|
-
}).catch((err) => logger$
|
|
15954
|
+
}).catch((err) => logger$26.warn({
|
|
16542
15955
|
err,
|
|
16543
15956
|
storyKey
|
|
16544
15957
|
}, "appendRecoveryEntry(tier-b) failed — pipeline continues"));
|
|
@@ -16558,7 +15971,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16558
15971
|
await persistState();
|
|
16559
15972
|
return "verification-failed";
|
|
16560
15973
|
} else if (recoveryResult?.action === "halt") {
|
|
16561
|
-
logger$
|
|
15974
|
+
logger$26.warn({ storyKey }, "Recovery Engine Tier C: halt — invoking interactive prompt for operator decision");
|
|
16562
15975
|
const haltRunId = config.pipelineRunId ?? storyKey;
|
|
16563
15976
|
await runInteractivePrompt({
|
|
16564
15977
|
runId: haltRunId,
|
|
@@ -16575,7 +15988,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16575
15988
|
eventBus.emit("decision:halt-skipped-non-interactive", haltPayload);
|
|
16576
15989
|
}
|
|
16577
15990
|
}).catch((err) => {
|
|
16578
|
-
logger$
|
|
15991
|
+
logger$26.warn({
|
|
16579
15992
|
err,
|
|
16580
15993
|
storyKey
|
|
16581
15994
|
}, "Recovery Engine Tier C: interactive prompt failed — escalating anyway");
|
|
@@ -16588,7 +16001,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16588
16001
|
outcome: "escalated",
|
|
16589
16002
|
cost_usd: 0,
|
|
16590
16003
|
timestamp: new Date().toISOString()
|
|
16591
|
-
}).catch((err) => logger$
|
|
16004
|
+
}).catch((err) => logger$26.warn({
|
|
16592
16005
|
err,
|
|
16593
16006
|
storyKey
|
|
16594
16007
|
}, "appendRecoveryEntry(tier-c) failed — pipeline continues"));
|
|
@@ -16613,11 +16026,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
16613
16026
|
if (effectiveProjectRoot !== void 0 && effectiveProjectRoot !== projectRoot) {
|
|
16614
16027
|
const cp = await checkpointStoryWorktree(storyKey, `verification-failed: ${verificationFailReason ?? "tier-a-fail"}`, effectiveProjectRoot);
|
|
16615
16028
|
if (cp.status === "committed") {
|
|
16616
|
-
logger$
|
|
16029
|
+
logger$26.info({
|
|
16617
16030
|
storyKey,
|
|
16618
16031
|
sha: cp.sha
|
|
16619
16032
|
}, "verification-failed checkpoint: uncommitted worktree state preserved on story branch");
|
|
16620
|
-
if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$
|
|
16033
|
+
if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$26.warn({
|
|
16621
16034
|
err,
|
|
16622
16035
|
storyKey
|
|
16623
16036
|
}, "patchStoryState(checkpoint_sha, verification-failed) failed — pipeline continues"));
|
|
@@ -16627,7 +16040,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16627
16040
|
phase: "VERIFICATION_FAILED",
|
|
16628
16041
|
completedAt: new Date().toISOString()
|
|
16629
16042
|
});
|
|
16630
|
-
if (runManifest !== null) runManifest.patchStoryState(storyKey, { escalation_reason: verificationFailReason }).catch((err) => logger$
|
|
16043
|
+
if (runManifest !== null) runManifest.patchStoryState(storyKey, { escalation_reason: verificationFailReason }).catch((err) => logger$26.warn({
|
|
16631
16044
|
err,
|
|
16632
16045
|
storyKey
|
|
16633
16046
|
}, "patchStoryState(escalation_reason, verification-failed) failed — pipeline continues"));
|
|
@@ -16653,7 +16066,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16653
16066
|
if (autoApprove?.downgradeLastVerdict !== void 0) completeUpdate.lastVerdict = autoApprove.downgradeLastVerdict;
|
|
16654
16067
|
updateStory(storyKey, completeUpdate);
|
|
16655
16068
|
if (config.skipVerification !== true && runManifest != null) Promise.resolve().then(() => runManifest.read()).then((manifest) => {
|
|
16656
|
-
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$
|
|
16069
|
+
if (manifest?.per_story_state?.[storyKey]?.verification_result == null) logger$26.warn({
|
|
16657
16070
|
storyKey,
|
|
16658
16071
|
category: "verification-result-missing"
|
|
16659
16072
|
}, "post-COMPLETE invariant: verification_result absent in manifest");
|
|
@@ -16676,7 +16089,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16676
16089
|
const commitResult = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirty, effectiveProjectRoot);
|
|
16677
16090
|
if (commitResult.status === "no-changes") {
|
|
16678
16091
|
if (_devOutputCommitHookFailure !== void 0) {
|
|
16679
|
-
logger$
|
|
16092
|
+
logger$26.error({
|
|
16680
16093
|
storyKey,
|
|
16681
16094
|
stderr: _devOutputCommitHookFailure
|
|
16682
16095
|
}, "deliverable commit was rejected by hooks at dev-story end and was never resolved — escalating");
|
|
@@ -16709,7 +16122,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16709
16122
|
branchAdvancedSinceBaseline = headNow !== baselineHeadSha;
|
|
16710
16123
|
} catch {}
|
|
16711
16124
|
if (!branchAdvancedSinceBaseline) {
|
|
16712
|
-
logger$
|
|
16125
|
+
logger$26.warn({
|
|
16713
16126
|
storyKey,
|
|
16714
16127
|
reason: commitResult.reason
|
|
16715
16128
|
}, "dev-story produced no committable changes — escalating instead of running merge-to-main on an unchanged branch");
|
|
@@ -16727,10 +16140,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
16727
16140
|
await persistState();
|
|
16728
16141
|
return "terminal";
|
|
16729
16142
|
}
|
|
16730
|
-
logger$
|
|
16143
|
+
logger$26.info({ storyKey }, "working tree clean at finalize but branch already advanced (commit-first) — proceeding to merge");
|
|
16731
16144
|
}
|
|
16732
16145
|
if (commitResult.status === "failed") {
|
|
16733
|
-
logger$
|
|
16146
|
+
logger$26.error({
|
|
16734
16147
|
storyKey,
|
|
16735
16148
|
stderr: commitResult.stderr
|
|
16736
16149
|
}, "substrate auto-commit failed — escalating story");
|
|
@@ -16751,7 +16164,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16751
16164
|
let finalizeCommitSha;
|
|
16752
16165
|
if (commitResult.status === "committed") {
|
|
16753
16166
|
finalizeCommitSha = commitResult.sha || void 0;
|
|
16754
|
-
logger$
|
|
16167
|
+
logger$26.info({
|
|
16755
16168
|
storyKey,
|
|
16756
16169
|
sha: commitResult.sha,
|
|
16757
16170
|
fileCount: commitResult.filesStaged.length
|
|
@@ -16779,7 +16192,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16779
16192
|
if (storyFilePath !== void 0) try {
|
|
16780
16193
|
Object.assign(statePatch, captureReconstructionInput(storyFilePath, storyKey, runManifest.baseDir, runManifest.runId, effectiveProjectRoot));
|
|
16781
16194
|
} catch (inputErr) {
|
|
16782
|
-
logger$
|
|
16195
|
+
logger$26.warn({
|
|
16783
16196
|
err: inputErr,
|
|
16784
16197
|
storyKey
|
|
16785
16198
|
}, "reconstruction phase-input capture failed — pipeline continues (commit_sha still recorded)");
|
|
@@ -16789,12 +16202,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
16789
16202
|
if (dispatchTelemetry.total_turns !== void 0) statePatch.total_turns = dispatchTelemetry.total_turns;
|
|
16790
16203
|
if (dispatchTelemetry.total_tokens !== void 0) statePatch.total_tokens = dispatchTelemetry.total_tokens;
|
|
16791
16204
|
} catch (telemetryErr) {
|
|
16792
|
-
logger$
|
|
16205
|
+
logger$26.warn({
|
|
16793
16206
|
err: telemetryErr,
|
|
16794
16207
|
storyKey
|
|
16795
16208
|
}, "aggregateStoryDispatchTelemetry failed — pipeline continues (commit_sha still recorded)");
|
|
16796
16209
|
}
|
|
16797
|
-
runManifest.patchStoryState(storyKey, statePatch).catch((err) => logger$
|
|
16210
|
+
runManifest.patchStoryState(storyKey, statePatch).catch((err) => logger$26.warn({
|
|
16798
16211
|
err,
|
|
16799
16212
|
storyKey
|
|
16800
16213
|
}, "patchStoryState(commit_sha/phase-input/telemetry) failed — pipeline continues"));
|
|
@@ -16822,7 +16235,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16822
16235
|
timeout: 5e3
|
|
16823
16236
|
}).trim();
|
|
16824
16237
|
if (branchSha === startSha) {
|
|
16825
|
-
logger$
|
|
16238
|
+
logger$26.warn({
|
|
16826
16239
|
storyKey,
|
|
16827
16240
|
branchSha,
|
|
16828
16241
|
startSha,
|
|
@@ -16843,7 +16256,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16843
16256
|
return "terminal";
|
|
16844
16257
|
}
|
|
16845
16258
|
} catch (gateErr) {
|
|
16846
|
-
logger$
|
|
16259
|
+
logger$26.warn({
|
|
16847
16260
|
storyKey,
|
|
16848
16261
|
err: gateErr instanceof Error ? gateErr.message : String(gateErr)
|
|
16849
16262
|
}, "merge-to-main pre-flight verification failed — proceeding with merge phase");
|
|
@@ -16861,7 +16274,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16861
16274
|
const artifactSet = new Set(artifactOnly.map(norm));
|
|
16862
16275
|
const undisclosed = mergedFiles.map(norm).filter((f$1) => !artifactSet.has(f$1) && !disclosed.has(f$1));
|
|
16863
16276
|
if (undisclosed.length > 0) {
|
|
16864
|
-
logger$
|
|
16277
|
+
logger$26.error({
|
|
16865
16278
|
storyKey,
|
|
16866
16279
|
undisclosed,
|
|
16867
16280
|
disclosed: [...disclosed]
|
|
@@ -16885,20 +16298,23 @@ function createImplementationOrchestrator(deps) {
|
|
|
16885
16298
|
try {
|
|
16886
16299
|
acceptanceOutcomes = await runAcceptanceStage(storyKey, effectiveProjectRoot ?? projectRoot ?? process.cwd());
|
|
16887
16300
|
} catch (stageErr) {
|
|
16888
|
-
logger$
|
|
16301
|
+
logger$26.warn({
|
|
16889
16302
|
storyKey,
|
|
16890
16303
|
err: stageErr
|
|
16891
16304
|
}, "A2.3: acceptance stage threw (best-effort) — claimed journeys stay unwalked");
|
|
16892
16305
|
}
|
|
16893
16306
|
let finalizationMode = config.finalizationMode ?? "merge";
|
|
16894
|
-
if ((
|
|
16307
|
+
if (resolveAcceptanceMode() === "blocking" && acceptanceOutcomes.length > 0) {
|
|
16895
16308
|
const criticalFailed = acceptanceOutcomes.filter((o) => o.criticality === "critical" && o.judged && !o.pass);
|
|
16896
16309
|
if (criticalFailed.length > 0) {
|
|
16897
16310
|
const failedIds = criticalFailed.map((o) => o.journeyId);
|
|
16898
|
-
logger$
|
|
16311
|
+
logger$26.error({
|
|
16899
16312
|
storyKey,
|
|
16900
16313
|
journeys: failedIds
|
|
16901
16314
|
}, "A4.1: journey-critical acceptance FAIL — blocking integration; branch preserved");
|
|
16315
|
+
if (projectRoot !== void 0) try {
|
|
16316
|
+
recordCriticalFail(projectRoot);
|
|
16317
|
+
} catch {}
|
|
16902
16318
|
updateStory(storyKey, {
|
|
16903
16319
|
phase: "ESCALATED",
|
|
16904
16320
|
error: "acceptance-fail",
|
|
@@ -16915,7 +16331,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16915
16331
|
}
|
|
16916
16332
|
const standardFailed = acceptanceOutcomes.filter((o) => o.criticality === "standard" && o.judged && !o.pass);
|
|
16917
16333
|
if (standardFailed.length > 0) {
|
|
16918
|
-
logger$
|
|
16334
|
+
logger$26.warn({
|
|
16919
16335
|
storyKey,
|
|
16920
16336
|
journeys: standardFailed.map((o) => o.journeyId)
|
|
16921
16337
|
}, "A4.1: standard-tier acceptance FAIL — run continues; fix-story proposal filed (best-effort)");
|
|
@@ -16925,7 +16341,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16925
16341
|
description: `standard-tier journey acceptance FAILED (${standardFailed.map((o) => o.journeyId).join(", ")}) — file a fix story to wire the journey end-states`,
|
|
16926
16342
|
type: "fix",
|
|
16927
16343
|
story_key: storyKey
|
|
16928
|
-
}).catch((err) => logger$
|
|
16344
|
+
}).catch((err) => logger$26.warn({
|
|
16929
16345
|
err,
|
|
16930
16346
|
storyKey
|
|
16931
16347
|
}, "A4.1: proposal append failed — pipeline continues"));
|
|
@@ -16933,7 +16349,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16933
16349
|
const critical = acceptanceOutcomes.filter((o) => o.criticality === "critical");
|
|
16934
16350
|
if (finalizationMode === "merge" && critical.length > 0 && critical.every((o) => o.judged && o.pass)) {
|
|
16935
16351
|
finalizationMode = config.acceptanceCriticalPassFinalization ?? "branch";
|
|
16936
|
-
logger$
|
|
16352
|
+
logger$26.info({
|
|
16937
16353
|
storyKey,
|
|
16938
16354
|
journeys: critical.map((o) => o.journeyId),
|
|
16939
16355
|
finalizationMode
|
|
@@ -16941,7 +16357,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16941
16357
|
}
|
|
16942
16358
|
}
|
|
16943
16359
|
{
|
|
16944
|
-
const acceptanceModeCfg =
|
|
16360
|
+
const acceptanceModeCfg = resolveAcceptanceMode();
|
|
16945
16361
|
if (acceptanceModeCfg !== "off") {
|
|
16946
16362
|
const epicOfA = (key) => key.includes("-") ? key.slice(0, key.lastIndexOf("-")) : key;
|
|
16947
16363
|
const epicIdA = epicOfA(storyKey);
|
|
@@ -16956,7 +16372,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16956
16372
|
if (audit?.unrunnable !== void 0) issueLines.push(audit.unrunnable);
|
|
16957
16373
|
if (acceptanceModeCfg === "blocking") {
|
|
16958
16374
|
const verdict = violations.some((v) => v.state === "unclaimed") ? "journey-unclaimed" : audit?.unrunnable !== void 0 ? "acceptance-unrunnable" : "journey-unwalked";
|
|
16959
|
-
logger$
|
|
16375
|
+
logger$26.error({
|
|
16960
16376
|
storyKey,
|
|
16961
16377
|
epicId: epicIdA,
|
|
16962
16378
|
verdict,
|
|
@@ -16980,7 +16396,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16980
16396
|
await persistState();
|
|
16981
16397
|
return "terminal";
|
|
16982
16398
|
}
|
|
16983
|
-
logger$
|
|
16399
|
+
logger$26.warn({
|
|
16984
16400
|
storyKey,
|
|
16985
16401
|
epicId: epicIdA,
|
|
16986
16402
|
violations: issueLines
|
|
@@ -16996,7 +16412,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
16996
16412
|
const TERMINAL_PHASES = ["COMPLETE", "ESCALATED"];
|
|
16997
16413
|
const isLastOfEpic = [..._stories.entries()].filter(([key]) => key !== storyKey && epicOf(key) === epicId).every(([, st]) => TERMINAL_PHASES.includes(st.phase));
|
|
16998
16414
|
if (isLastOfEpic) {
|
|
16999
|
-
logger$
|
|
16415
|
+
logger$26.info({
|
|
17000
16416
|
storyKey,
|
|
17001
16417
|
epicId,
|
|
17002
16418
|
epicGateCommand
|
|
@@ -17021,7 +16437,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17021
16437
|
gateOutput = `${e.stdout ?? ""}${e.stderr ?? ""}`.trim() || (e.message ?? String(gateCmdErr));
|
|
17022
16438
|
}
|
|
17023
16439
|
if (!gatePassed) {
|
|
17024
|
-
logger$
|
|
16440
|
+
logger$26.error({
|
|
17025
16441
|
storyKey,
|
|
17026
16442
|
epicId,
|
|
17027
16443
|
output: gateOutput.slice(0, 500)
|
|
@@ -17040,7 +16456,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17040
16456
|
await persistState();
|
|
17041
16457
|
return "terminal";
|
|
17042
16458
|
}
|
|
17043
|
-
logger$
|
|
16459
|
+
logger$26.info({
|
|
17044
16460
|
storyKey,
|
|
17045
16461
|
epicId
|
|
17046
16462
|
}, "H3.4: epic gate passed");
|
|
@@ -17085,7 +16501,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17085
16501
|
}).trim();
|
|
17086
16502
|
prUrl = ghOutput === "" ? void 0 : ghOutput;
|
|
17087
16503
|
} catch (prErr) {
|
|
17088
|
-
logger$
|
|
16504
|
+
logger$26.warn({
|
|
17089
16505
|
storyKey,
|
|
17090
16506
|
branchName,
|
|
17091
16507
|
err: prErr instanceof Error ? prErr.message.slice(0, 300) : String(prErr)
|
|
@@ -17094,7 +16510,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17094
16510
|
try {
|
|
17095
16511
|
await _worktreeManager.cleanupWorktree(storyKey, { keepBranch: true });
|
|
17096
16512
|
} catch (cleanupErr) {
|
|
17097
|
-
logger$
|
|
16513
|
+
logger$26.warn({
|
|
17098
16514
|
storyKey,
|
|
17099
16515
|
err: cleanupErr
|
|
17100
16516
|
}, "worktree removal after branch/pr finalization failed (best-effort; branch intact)");
|
|
@@ -17111,11 +16527,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
17111
16527
|
branch: branchName,
|
|
17112
16528
|
...storyDeliverableSha ? { sha: storyDeliverableSha } : {},
|
|
17113
16529
|
...prUrl !== void 0 ? { pr_url: prUrl } : {}
|
|
17114
|
-
} }).catch((err) => logger$
|
|
16530
|
+
} }).catch((err) => logger$26.warn({
|
|
17115
16531
|
err,
|
|
17116
16532
|
storyKey
|
|
17117
16533
|
}, "patchStoryState(finalization) failed — pipeline continues"));
|
|
17118
|
-
logger$
|
|
16534
|
+
logger$26.info({
|
|
17119
16535
|
storyKey,
|
|
17120
16536
|
branchName,
|
|
17121
16537
|
mode: finalizationMode,
|
|
@@ -17123,7 +16539,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17123
16539
|
}, "story finalized without self-merge — branch is the deliverable");
|
|
17124
16540
|
return "finalized";
|
|
17125
16541
|
}
|
|
17126
|
-
logger$
|
|
16542
|
+
logger$26.info({
|
|
17127
16543
|
storyKey,
|
|
17128
16544
|
branchName,
|
|
17129
16545
|
startBranch: _orchestratorStartBranch
|
|
@@ -17141,7 +16557,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17141
16557
|
});
|
|
17142
16558
|
} catch (mergeErr) {
|
|
17143
16559
|
const errMsg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
17144
|
-
logger$
|
|
16560
|
+
logger$26.error({
|
|
17145
16561
|
storyKey,
|
|
17146
16562
|
err: mergeErr
|
|
17147
16563
|
}, "merge-to-main phase threw unexpectedly — escalating story");
|
|
@@ -17165,7 +16581,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17165
16581
|
if (failReason === "parent-tree-dirtied-by-run") issues.push(`parent working tree has uncommitted changes to ${mergeResult.dirtiedFiles?.length ?? 0} file(s) the story also modified: ${(mergeResult.dirtiedFiles ?? []).join(", ")} — merging would entangle unreviewed parent edits with verified story content. Commit or stash the parent changes, then merge ${branchName} manually.`);
|
|
17166
16582
|
else if (failReason === "ff-only-merge-not-possible") issues.push(`${_orchestratorStartBranch ?? "the start branch"} moved since ${branchName} was created and merge_strategy is ff-only — substrate will not synthesize a merge commit. Set finalization.merge_strategy: three-way (required for concurrent multi-story runs) or integrate the branch manually.`);
|
|
17167
16583
|
else issues.push(`merge conflict in ${mergeResult.conflictingFiles?.length ?? 0} file(s): ${(mergeResult.conflictingFiles ?? []).join(", ")}`);
|
|
17168
|
-
logger$
|
|
16584
|
+
logger$26.warn({
|
|
17169
16585
|
storyKey,
|
|
17170
16586
|
branchName,
|
|
17171
16587
|
reason: failReason,
|
|
@@ -17186,7 +16602,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17186
16602
|
await persistState();
|
|
17187
16603
|
return "terminal";
|
|
17188
16604
|
}
|
|
17189
|
-
logger$
|
|
16605
|
+
logger$26.info({
|
|
17190
16606
|
storyKey,
|
|
17191
16607
|
branchName
|
|
17192
16608
|
}, "merge-to-main phase completed successfully");
|
|
@@ -17205,7 +16621,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17205
16621
|
mode: "merge",
|
|
17206
16622
|
branch: branchName,
|
|
17207
16623
|
...storyDeliverableSha ? { sha: storyDeliverableSha } : {}
|
|
17208
|
-
} }).catch((err) => logger$
|
|
16624
|
+
} }).catch((err) => logger$26.warn({
|
|
17209
16625
|
err,
|
|
17210
16626
|
storyKey
|
|
17211
16627
|
}, "patchStoryState(finalization) failed — pipeline continues"));
|
|
@@ -17267,7 +16683,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17267
16683
|
"NEEDS_MAJOR_REWORK": 2
|
|
17268
16684
|
};
|
|
17269
16685
|
for (const group of batchFileGroups) {
|
|
17270
|
-
logger$
|
|
16686
|
+
logger$26.info({
|
|
17271
16687
|
storyKey,
|
|
17272
16688
|
batchIndex: group.batchIndex,
|
|
17273
16689
|
fileCount: group.files.length
|
|
@@ -17313,7 +16729,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17313
16729
|
rawOutput: lastRawOutput,
|
|
17314
16730
|
tokenUsage: aggregateTokens
|
|
17315
16731
|
};
|
|
17316
|
-
logger$
|
|
16732
|
+
logger$26.info({
|
|
17317
16733
|
storyKey,
|
|
17318
16734
|
batchCount: batchFileGroups.length,
|
|
17319
16735
|
verdict: worstVerdict,
|
|
@@ -17357,7 +16773,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17357
16773
|
storyKey,
|
|
17358
16774
|
reviewCycle: reviewCycles
|
|
17359
16775
|
})
|
|
17360
|
-
})).catch((tokenErr) => logger$
|
|
16776
|
+
})).catch((tokenErr) => logger$26.warn({
|
|
17361
16777
|
storyKey,
|
|
17362
16778
|
err: tokenErr
|
|
17363
16779
|
}, "Failed to record code-review token usage"));
|
|
@@ -17375,7 +16791,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17375
16791
|
...reviewResult.details !== void 0 ? { details: reviewResult.details } : {}
|
|
17376
16792
|
});
|
|
17377
16793
|
if (schemaValidationRetries <= MAX_SCHEMA_VALIDATION_RETRIES) {
|
|
17378
|
-
logger$
|
|
16794
|
+
logger$26.warn({
|
|
17379
16795
|
storyKey,
|
|
17380
16796
|
reviewCycles,
|
|
17381
16797
|
attempt: schemaValidationRetries,
|
|
@@ -17384,7 +16800,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17384
16800
|
previousIterationWasMalformed = true;
|
|
17385
16801
|
continue;
|
|
17386
16802
|
}
|
|
17387
|
-
logger$
|
|
16803
|
+
logger$26.warn({
|
|
17388
16804
|
storyKey,
|
|
17389
16805
|
reviewCycles,
|
|
17390
16806
|
schemaValidationRetries
|
|
@@ -17407,7 +16823,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17407
16823
|
}
|
|
17408
16824
|
if (isPhantomReview && !timeoutRetried) {
|
|
17409
16825
|
timeoutRetried = true;
|
|
17410
|
-
logger$
|
|
16826
|
+
logger$26.warn({
|
|
17411
16827
|
storyKey,
|
|
17412
16828
|
reviewCycles,
|
|
17413
16829
|
error: reviewResult.error
|
|
@@ -17437,7 +16853,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17437
16853
|
}
|
|
17438
16854
|
const isStoryFileMissing = (reviewResult.error ?? "").includes("story-file-missing");
|
|
17439
16855
|
const escalationReason = isStoryFileMissing ? "story-file-missing" : "consecutive-review-timeouts";
|
|
17440
|
-
logger$
|
|
16856
|
+
logger$26.warn({
|
|
17441
16857
|
storyKey,
|
|
17442
16858
|
reviewCycles,
|
|
17443
16859
|
error: reviewResult.error,
|
|
@@ -17462,7 +16878,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17462
16878
|
verdict = reviewResult.verdict;
|
|
17463
16879
|
issueList = reviewResult.issue_list ?? [];
|
|
17464
16880
|
if (verdict === "NEEDS_MAJOR_REWORK" && reviewCycles > 0 && previousIssueList.length > 0 && issueList.length < previousIssueList.length) {
|
|
17465
|
-
logger$
|
|
16881
|
+
logger$26.info({
|
|
17466
16882
|
storyKey,
|
|
17467
16883
|
originalVerdict: verdict,
|
|
17468
16884
|
issuesBefore: previousIssueList.length,
|
|
@@ -17491,7 +16907,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17491
16907
|
await persistState();
|
|
17492
16908
|
if (runManifest !== null) {
|
|
17493
16909
|
const persistedVerdict = reviewResult.agentVerdict ?? verdict;
|
|
17494
|
-
runManifest.patchStoryState(storyKey, { verdict: persistedVerdict }).catch((err) => logger$
|
|
16910
|
+
runManifest.patchStoryState(storyKey, { verdict: persistedVerdict }).catch((err) => logger$26.warn({
|
|
17495
16911
|
err,
|
|
17496
16912
|
storyKey
|
|
17497
16913
|
}, "patchStoryState(verdict) failed — pipeline continues"));
|
|
@@ -17505,7 +16921,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17505
16921
|
if (_decomposition !== void 0) parts.push(`decomposed: ${_decomposition.batchCount} batches`);
|
|
17506
16922
|
parts.push(`${fileCount} files`);
|
|
17507
16923
|
parts.push(`${totalTokensK} tokens`);
|
|
17508
|
-
logger$
|
|
16924
|
+
logger$26.info({
|
|
17509
16925
|
storyKey,
|
|
17510
16926
|
verdict,
|
|
17511
16927
|
agentVerdict: reviewResult.agentVerdict
|
|
@@ -17568,9 +16984,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
17568
16984
|
}),
|
|
17569
16985
|
rationale: `Advisory notes from LGTM_WITH_NOTES review of ${storyKey}`
|
|
17570
16986
|
});
|
|
17571
|
-
logger$
|
|
16987
|
+
logger$26.info({ storyKey }, "Advisory notes persisted to decision store");
|
|
17572
16988
|
} catch (advisoryErr) {
|
|
17573
|
-
logger$
|
|
16989
|
+
logger$26.warn({
|
|
17574
16990
|
storyKey,
|
|
17575
16991
|
error: advisoryErr instanceof Error ? advisoryErr.message : String(advisoryErr)
|
|
17576
16992
|
}, "Failed to persist advisory notes (best-effort)");
|
|
@@ -17578,27 +16994,27 @@ function createImplementationOrchestrator(deps) {
|
|
|
17578
16994
|
if (telemetryPersistence !== void 0) try {
|
|
17579
16995
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
17580
16996
|
if (turns.length > 0) {
|
|
17581
|
-
const scorer = new EfficiencyScorer(logger$
|
|
16997
|
+
const scorer = new EfficiencyScorer(logger$26);
|
|
17582
16998
|
const effScore = scorer.score(storyKey, turns);
|
|
17583
16999
|
await telemetryPersistence.storeEfficiencyScore(effScore);
|
|
17584
|
-
logger$
|
|
17000
|
+
logger$26.info({
|
|
17585
17001
|
storyKey,
|
|
17586
17002
|
compositeScore: effScore.compositeScore,
|
|
17587
17003
|
modelCount: effScore.perModelBreakdown.length
|
|
17588
17004
|
}, "Efficiency score computed and persisted");
|
|
17589
|
-
} else logger$
|
|
17005
|
+
} else logger$26.debug({ storyKey }, "No turn analysis data available — skipping efficiency scoring");
|
|
17590
17006
|
} catch (effErr) {
|
|
17591
|
-
logger$
|
|
17007
|
+
logger$26.warn({
|
|
17592
17008
|
storyKey,
|
|
17593
17009
|
error: effErr instanceof Error ? effErr.message : String(effErr)
|
|
17594
17010
|
}, "Efficiency scoring failed — story verdict unchanged");
|
|
17595
17011
|
}
|
|
17596
17012
|
if (telemetryPersistence !== void 0) try {
|
|
17597
17013
|
const turns = await telemetryPersistence.getTurnAnalysis(storyKey);
|
|
17598
|
-
if (turns.length === 0) logger$
|
|
17014
|
+
if (turns.length === 0) logger$26.debug({ storyKey }, "No turn analysis data for telemetry categorization — skipping");
|
|
17599
17015
|
else {
|
|
17600
|
-
const categorizer = new Categorizer(logger$
|
|
17601
|
-
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$
|
|
17016
|
+
const categorizer = new Categorizer(logger$26);
|
|
17017
|
+
const consumerAnalyzer = new ConsumerAnalyzer(categorizer, logger$26);
|
|
17602
17018
|
const categoryStats = categorizer.computeCategoryStatsFromTurns(turns);
|
|
17603
17019
|
const consumerStats = consumerAnalyzer.analyzeFromTurns(turns);
|
|
17604
17020
|
await telemetryPersistence.storeCategoryStats(storyKey, categoryStats);
|
|
@@ -17606,7 +17022,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17606
17022
|
const growingCount = categoryStats.filter((c) => c.trend === "growing").length;
|
|
17607
17023
|
const topCategory = categoryStats[0]?.category ?? "none";
|
|
17608
17024
|
const topConsumer = consumerStats[0]?.consumerKey ?? "none";
|
|
17609
|
-
logger$
|
|
17025
|
+
logger$26.info({
|
|
17610
17026
|
storyKey,
|
|
17611
17027
|
topCategory,
|
|
17612
17028
|
topConsumer,
|
|
@@ -17614,7 +17030,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17614
17030
|
}, "Semantic categorization and consumer analysis complete");
|
|
17615
17031
|
}
|
|
17616
17032
|
} catch (catErr) {
|
|
17617
|
-
logger$
|
|
17033
|
+
logger$26.warn({
|
|
17618
17034
|
storyKey,
|
|
17619
17035
|
error: catErr instanceof Error ? catErr.message : String(catErr)
|
|
17620
17036
|
}, "Semantic categorization failed — story verdict unchanged");
|
|
@@ -17637,7 +17053,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17637
17053
|
filesModified: devFilesModified,
|
|
17638
17054
|
workingDirectory: effectiveProjectRoot
|
|
17639
17055
|
});
|
|
17640
|
-
logger$
|
|
17056
|
+
logger$26.debug({
|
|
17641
17057
|
storyKey,
|
|
17642
17058
|
expansion_priority: expansionResult.expansion_priority,
|
|
17643
17059
|
coverage_gaps: expansionResult.coverage_gaps.length
|
|
@@ -17650,7 +17066,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17650
17066
|
value: JSON.stringify(expansionResult)
|
|
17651
17067
|
});
|
|
17652
17068
|
} catch (expansionErr) {
|
|
17653
|
-
logger$
|
|
17069
|
+
logger$26.warn({
|
|
17654
17070
|
storyKey,
|
|
17655
17071
|
error: expansionErr instanceof Error ? expansionErr.message : String(expansionErr)
|
|
17656
17072
|
}, "Test expansion failed — story verdict unchanged");
|
|
@@ -17679,7 +17095,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17679
17095
|
await persistState();
|
|
17680
17096
|
return;
|
|
17681
17097
|
}
|
|
17682
|
-
logger$
|
|
17098
|
+
logger$26.info({
|
|
17683
17099
|
storyKey,
|
|
17684
17100
|
reviewCycles: finalReviewCycles,
|
|
17685
17101
|
issueCount: issueList.length
|
|
@@ -17745,7 +17161,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17745
17161
|
fixPrompt = assembled.prompt;
|
|
17746
17162
|
} catch {
|
|
17747
17163
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, minor fixes needed`;
|
|
17748
|
-
logger$
|
|
17164
|
+
logger$26.warn({ storyKey }, "Failed to assemble auto-approve fix prompt, using fallback");
|
|
17749
17165
|
}
|
|
17750
17166
|
const handle = dispatcher.dispatch({
|
|
17751
17167
|
prompt: fixPrompt,
|
|
@@ -17770,9 +17186,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
17770
17186
|
output: fixResult.tokenEstimate.output
|
|
17771
17187
|
} : void 0 }
|
|
17772
17188
|
});
|
|
17773
|
-
if (fixResult.status === "timeout") logger$
|
|
17189
|
+
if (fixResult.status === "timeout") logger$26.warn({ storyKey }, "Auto-approve fix timed out — approving anyway (issues were minor)");
|
|
17774
17190
|
} catch (err) {
|
|
17775
|
-
logger$
|
|
17191
|
+
logger$26.warn({
|
|
17776
17192
|
storyKey,
|
|
17777
17193
|
err
|
|
17778
17194
|
}, "Auto-approve fix dispatch failed — approving anyway (issues were minor)");
|
|
@@ -17801,7 +17217,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17801
17217
|
outcome: "retried",
|
|
17802
17218
|
cost_usd: 0,
|
|
17803
17219
|
timestamp: new Date().toISOString()
|
|
17804
|
-
}).catch((err) => logger$
|
|
17220
|
+
}).catch((err) => logger$26.warn({
|
|
17805
17221
|
err,
|
|
17806
17222
|
storyKey
|
|
17807
17223
|
}, "appendRecoveryEntry failed — pipeline continues"));
|
|
@@ -17941,7 +17357,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17941
17357
|
fixPrompt = assembled.prompt;
|
|
17942
17358
|
} catch {
|
|
17943
17359
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, taskType=${taskType}`;
|
|
17944
|
-
logger$
|
|
17360
|
+
logger$26.warn({
|
|
17945
17361
|
storyKey,
|
|
17946
17362
|
taskType
|
|
17947
17363
|
}, "Failed to assemble fix prompt, using fallback");
|
|
@@ -17985,7 +17401,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
17985
17401
|
if (taskType === "minor-fixes") {
|
|
17986
17402
|
const finalReviewCycles = reviewCycles + 1;
|
|
17987
17403
|
const downgradedVerdict = "LGTM_WITH_NOTES";
|
|
17988
|
-
logger$
|
|
17404
|
+
logger$26.warn({
|
|
17989
17405
|
storyKey,
|
|
17990
17406
|
reviewCycles: finalReviewCycles,
|
|
17991
17407
|
issueCount: issueList.length
|
|
@@ -18005,7 +17421,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18005
17421
|
keepReviewing = false;
|
|
18006
17422
|
return;
|
|
18007
17423
|
}
|
|
18008
|
-
logger$
|
|
17424
|
+
logger$26.warn({
|
|
18009
17425
|
storyKey,
|
|
18010
17426
|
taskType
|
|
18011
17427
|
}, "Fix dispatch timed out — escalating story");
|
|
@@ -18027,7 +17443,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18027
17443
|
}
|
|
18028
17444
|
if (fixResult.status === "failed") {
|
|
18029
17445
|
if (isMajorRework) {
|
|
18030
|
-
logger$
|
|
17446
|
+
logger$26.warn({
|
|
18031
17447
|
storyKey,
|
|
18032
17448
|
exitCode: fixResult.exitCode
|
|
18033
17449
|
}, "Major rework dispatch failed — escalating story");
|
|
@@ -18047,7 +17463,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18047
17463
|
await persistState();
|
|
18048
17464
|
return;
|
|
18049
17465
|
}
|
|
18050
|
-
logger$
|
|
17466
|
+
logger$26.warn({
|
|
18051
17467
|
storyKey,
|
|
18052
17468
|
taskType,
|
|
18053
17469
|
exitCode: fixResult.exitCode
|
|
@@ -18055,7 +17471,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18055
17471
|
}
|
|
18056
17472
|
if (isMajorRework) replaceDevStorySignals(fixResult.parsed);
|
|
18057
17473
|
} catch (err) {
|
|
18058
|
-
logger$
|
|
17474
|
+
logger$26.warn({
|
|
18059
17475
|
storyKey,
|
|
18060
17476
|
taskType,
|
|
18061
17477
|
err
|
|
@@ -18124,7 +17540,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18124
17540
|
eventBus.emit("decision:halt-skipped-non-interactive", payload);
|
|
18125
17541
|
}
|
|
18126
17542
|
}).catch((err) => {
|
|
18127
|
-
logger$
|
|
17543
|
+
logger$26.warn({ err }, "interactive prompt failed during auth-failure halt — halting anyway");
|
|
18128
17544
|
});
|
|
18129
17545
|
for (const [key, state] of _stories) if (state.phase === "PENDING" && key !== triggeredStoryKey) {
|
|
18130
17546
|
updateStory(key, {
|
|
@@ -18137,7 +17553,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18137
17553
|
escalation_reason: "auth-failure-halt"
|
|
18138
17554
|
}).catch(() => {});
|
|
18139
17555
|
}
|
|
18140
|
-
logger$
|
|
17556
|
+
logger$26.error({
|
|
18141
17557
|
runId,
|
|
18142
17558
|
triggeredStoryKey,
|
|
18143
17559
|
matchedSignature
|
|
@@ -18171,7 +17587,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18171
17587
|
eventBus.emit("decision:halt-skipped-non-interactive", payload);
|
|
18172
17588
|
}
|
|
18173
17589
|
}).catch((err) => {
|
|
18174
|
-
logger$
|
|
17590
|
+
logger$26.warn({ err }, "interactive prompt failed during cost-ceiling halt — continuing with default action");
|
|
18175
17591
|
});
|
|
18176
17592
|
} else eventBus.emit("decision:autonomous", {
|
|
18177
17593
|
runId,
|
|
@@ -18199,7 +17615,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18199
17615
|
severity: routeResult.severity
|
|
18200
17616
|
});
|
|
18201
17617
|
_budgetExhausted = true;
|
|
18202
|
-
logger$
|
|
17618
|
+
logger$26.warn({
|
|
18203
17619
|
skipped: allSkipped.length,
|
|
18204
17620
|
cumulative: result.cumulative,
|
|
18205
17621
|
ceiling: result.ceiling,
|
|
@@ -18218,7 +17634,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18218
17634
|
const completedStoryKeys = [];
|
|
18219
17635
|
for (const storyKey of group) {
|
|
18220
17636
|
if (_shutdownRequested) {
|
|
18221
|
-
logger$
|
|
17637
|
+
logger$26.info({ storyKey }, "shutdown requested — skipping dispatch");
|
|
18222
17638
|
return;
|
|
18223
17639
|
}
|
|
18224
17640
|
if (runManifest !== null && runManifest !== void 0) try {
|
|
@@ -18241,7 +17657,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18241
17657
|
}
|
|
18242
17658
|
}
|
|
18243
17659
|
} catch (err) {
|
|
18244
|
-
logger$
|
|
17660
|
+
logger$26.debug({ err }, "Cost ceiling check failed — proceeding without enforcement");
|
|
18245
17661
|
}
|
|
18246
17662
|
let optimizationDirectives;
|
|
18247
17663
|
if (telemetryAdvisor !== void 0 && completedStoryKeys.length > 0) try {
|
|
@@ -18249,13 +17665,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
18249
17665
|
const directives = telemetryAdvisor.formatOptimizationDirectives(recs);
|
|
18250
17666
|
if (directives.length > 0) {
|
|
18251
17667
|
optimizationDirectives = directives;
|
|
18252
|
-
logger$
|
|
17668
|
+
logger$26.debug({
|
|
18253
17669
|
storyKey,
|
|
18254
17670
|
directiveCount: recs.filter((r) => r.severity !== "info").length
|
|
18255
17671
|
}, "Optimization directives ready for dispatch");
|
|
18256
17672
|
}
|
|
18257
17673
|
} catch (err) {
|
|
18258
|
-
logger$
|
|
17674
|
+
logger$26.debug({
|
|
18259
17675
|
err,
|
|
18260
17676
|
storyKey
|
|
18261
17677
|
}, "Failed to fetch optimization directives — proceeding without");
|
|
@@ -18379,7 +17795,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18379
17795
|
recommendedAction: "serialize"
|
|
18380
17796
|
});
|
|
18381
17797
|
} catch {}
|
|
18382
|
-
logger$
|
|
17798
|
+
logger$26.info({
|
|
18383
17799
|
storyKeys: evt.storyKeys,
|
|
18384
17800
|
collisionPaths: evt.collisionPaths
|
|
18385
17801
|
}, "Cross-story file collision detected — serializing affected groups to prevent race conditions");
|
|
@@ -18392,7 +17808,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18392
17808
|
mergedGroupMap.set(root2, [...existing, ...group]);
|
|
18393
17809
|
}
|
|
18394
17810
|
const result = [...mergedGroupMap.values()];
|
|
18395
|
-
logger$
|
|
17811
|
+
logger$26.info({
|
|
18396
17812
|
originalGroupCount: batchGroups.length,
|
|
18397
17813
|
mergedGroupCount: result.length,
|
|
18398
17814
|
collisionCount
|
|
@@ -18436,7 +17852,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18436
17852
|
async function shutdownGracefully(reason, signal) {
|
|
18437
17853
|
if (_shutdownRequested) return;
|
|
18438
17854
|
_shutdownRequested = true;
|
|
18439
|
-
logger$
|
|
17855
|
+
logger$26.info({
|
|
18440
17856
|
reason,
|
|
18441
17857
|
signal
|
|
18442
17858
|
}, "Graceful shutdown initiated — stopping new dispatches");
|
|
@@ -18446,8 +17862,8 @@ function createImplementationOrchestrator(deps) {
|
|
|
18446
17862
|
run_status: "stopped",
|
|
18447
17863
|
stopped_reason: reason,
|
|
18448
17864
|
stopped_at: new Date().toISOString()
|
|
18449
|
-
}).catch((err) => logger$
|
|
18450
|
-
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$
|
|
17865
|
+
}).catch((err) => logger$26.warn({ err }, "patchRunStatus failed during shutdown (best-effort)"));
|
|
17866
|
+
if (config.pipelineRunId !== void 0) await updatePipelineRun(db, config.pipelineRunId, { status: "stopped" }).catch((err) => logger$26.warn({ err }, "updatePipelineRun(stopped) failed during shutdown (best-effort)"));
|
|
18451
17867
|
const activePhases = [
|
|
18452
17868
|
"PENDING",
|
|
18453
17869
|
"IN_STORY_CREATION",
|
|
@@ -18458,7 +17874,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18458
17874
|
"CHECKPOINT"
|
|
18459
17875
|
];
|
|
18460
17876
|
const cancellations = [];
|
|
18461
|
-
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$
|
|
17877
|
+
for (const [storyKey, state] of _stories.entries()) if (activePhases.includes(state.phase)) cancellations.push(wgRepo.updateStoryStatus(storyKey, "cancelled").catch((err) => logger$26.warn({
|
|
18462
17878
|
err,
|
|
18463
17879
|
storyKey
|
|
18464
17880
|
}, "wg_stories → cancelled failed during shutdown (best-effort)")));
|
|
@@ -18467,11 +17883,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
18467
17883
|
}
|
|
18468
17884
|
async function run(storyKeys) {
|
|
18469
17885
|
if (_state === "RUNNING" || _state === "PAUSED") {
|
|
18470
|
-
logger$
|
|
17886
|
+
logger$26.warn({ state: _state }, "run() called while orchestrator is already running or paused — ignoring");
|
|
18471
17887
|
return getStatus();
|
|
18472
17888
|
}
|
|
18473
17889
|
if (_state === "COMPLETE") {
|
|
18474
|
-
logger$
|
|
17890
|
+
logger$26.warn({ state: _state }, "run() called on a COMPLETE orchestrator — ignoring");
|
|
18475
17891
|
return getStatus();
|
|
18476
17892
|
}
|
|
18477
17893
|
_state = "RUNNING";
|
|
@@ -18486,15 +17902,36 @@ function createImplementationOrchestrator(deps) {
|
|
|
18486
17902
|
"pipe"
|
|
18487
17903
|
]
|
|
18488
17904
|
}).trim();
|
|
18489
|
-
logger$
|
|
17905
|
+
logger$26.info({ orchestratorStartBranch: _orchestratorStartBranch }, "Captured orchestrator start branch for merge-to-main");
|
|
17906
|
+
if ((config.acceptanceMode ?? "advisory") === "blocking") try {
|
|
17907
|
+
_runStartSha = execSync("git rev-parse HEAD", {
|
|
17908
|
+
cwd: projectRoot,
|
|
17909
|
+
encoding: "utf-8",
|
|
17910
|
+
stdio: [
|
|
17911
|
+
"ignore",
|
|
17912
|
+
"pipe",
|
|
17913
|
+
"pipe"
|
|
17914
|
+
]
|
|
17915
|
+
}).trim() || void 0;
|
|
17916
|
+
} catch {
|
|
17917
|
+
_runStartSha = void 0;
|
|
17918
|
+
}
|
|
17919
|
+
if (config.noWorktree === true && (config.acceptanceMode ?? "advisory") === "blocking") {
|
|
17920
|
+
const warnMsg = "acceptance-tamper-guard-disabled: --no-worktree + acceptance.mode blocking — the spec-tamper tripwire cannot function without worktree isolation (trusted == working tree). An agent can weaken journey specs undetected. Prefer worktree isolation for blocking-mode acceptance.";
|
|
17921
|
+
logger$26.warn({ storyScope: storyKeys }, warnMsg);
|
|
17922
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
17923
|
+
storyKey: "(run)",
|
|
17924
|
+
msg: warnMsg
|
|
17925
|
+
});
|
|
17926
|
+
}
|
|
18490
17927
|
} catch (branchErr) {
|
|
18491
17928
|
if (config.noWorktree !== true) {
|
|
18492
|
-
logger$
|
|
17929
|
+
logger$26.error({ err: branchErr }, "FATAL: failed to capture the orchestrator start branch (git rev-parse --abbrev-ref HEAD). Worktree finalization cannot work without it. Fix git in the project root or re-run with --no-worktree.");
|
|
18493
17930
|
_state = "FAILED";
|
|
18494
17931
|
_completedAt = new Date().toISOString();
|
|
18495
17932
|
return getStatus();
|
|
18496
17933
|
}
|
|
18497
|
-
logger$
|
|
17934
|
+
logger$26.warn({ err: branchErr }, "Failed to capture orchestrator start branch — merge-to-main will skip worktree integration (--no-worktree run)");
|
|
18498
17935
|
}
|
|
18499
17936
|
for (const key of storyKeys) {
|
|
18500
17937
|
const pendingState = {
|
|
@@ -18537,13 +17974,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
18537
17974
|
await persistState();
|
|
18538
17975
|
recordProgress();
|
|
18539
17976
|
if (config.enableHeartbeat) startHeartbeat();
|
|
18540
|
-
if (_orchestratorStartBranch !== void 0 && runManifest !== null) runManifest.patchRunStatus({ orchestrator_start_branch: _orchestratorStartBranch }).catch((err) => logger$
|
|
17977
|
+
if (_orchestratorStartBranch !== void 0 && runManifest !== null) runManifest.patchRunStatus({ orchestrator_start_branch: _orchestratorStartBranch }).catch((err) => logger$26.warn({ err }, "Failed to persist orchestrator_start_branch to manifest (best-effort)"));
|
|
18541
17978
|
const _startupTimings = {};
|
|
18542
17979
|
if (projectRoot !== void 0) {
|
|
18543
17980
|
const seedStart = Date.now();
|
|
18544
17981
|
const seedResult = await seedMethodologyContext(db, projectRoot);
|
|
18545
17982
|
_startupTimings.seedMethodologyMs = Date.now() - seedStart;
|
|
18546
|
-
if (seedResult.decisionsCreated > 0) logger$
|
|
17983
|
+
if (seedResult.decisionsCreated > 0) logger$26.info({
|
|
18547
17984
|
decisionsCreated: seedResult.decisionsCreated,
|
|
18548
17985
|
skippedCategories: seedResult.skippedCategories,
|
|
18549
17986
|
durationMs: _startupTimings.seedMethodologyMs
|
|
@@ -18553,12 +17990,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
18553
17990
|
const ingestStart = Date.now();
|
|
18554
17991
|
try {
|
|
18555
17992
|
const ingestResult = await autoIngestEpicsDependencies(db, projectRoot);
|
|
18556
|
-
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$
|
|
17993
|
+
if (ingestResult.storiesIngested > 0 || ingestResult.dependenciesIngested > 0) logger$26.info({
|
|
18557
17994
|
...ingestResult,
|
|
18558
17995
|
durationMs: Date.now() - ingestStart
|
|
18559
17996
|
}, "Auto-ingested stories and dependencies from epics document");
|
|
18560
17997
|
} catch (err) {
|
|
18561
|
-
logger$
|
|
17998
|
+
logger$26.debug({ err }, "Auto-ingest from epics document skipped — work graph may be unavailable");
|
|
18562
17999
|
}
|
|
18563
18000
|
}
|
|
18564
18001
|
const sigtermHandler = () => {
|
|
@@ -18572,7 +18009,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18572
18009
|
try {
|
|
18573
18010
|
if (ingestionServer !== void 0) {
|
|
18574
18011
|
if (telemetryPersistence !== void 0) try {
|
|
18575
|
-
const pipelineLogger = logger$
|
|
18012
|
+
const pipelineLogger = logger$26;
|
|
18576
18013
|
const telemetryPipeline = new TelemetryPipeline({
|
|
18577
18014
|
normalizer: new TelemetryNormalizer(pipelineLogger),
|
|
18578
18015
|
turnAnalyzer: new TurnAnalyzer(pipelineLogger),
|
|
@@ -18584,14 +18021,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
18584
18021
|
persistence: telemetryPersistence
|
|
18585
18022
|
});
|
|
18586
18023
|
ingestionServer.setPipeline(telemetryPipeline);
|
|
18587
|
-
logger$
|
|
18024
|
+
logger$26.info("TelemetryPipeline wired to IngestionServer");
|
|
18588
18025
|
} catch (pipelineErr) {
|
|
18589
|
-
logger$
|
|
18026
|
+
logger$26.warn({ err: pipelineErr }, "Failed to create TelemetryPipeline — continuing without analysis pipeline");
|
|
18590
18027
|
}
|
|
18591
|
-
await ingestionServer.start().catch((err) => logger$
|
|
18028
|
+
await ingestionServer.start().catch((err) => logger$26.warn({ err }, "IngestionServer.start() failed — continuing without telemetry (best-effort)"));
|
|
18592
18029
|
try {
|
|
18593
18030
|
_otlpEndpoint = ingestionServer.getOtlpEnvVars().OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
18594
|
-
logger$
|
|
18031
|
+
logger$26.info({ otlpEndpoint: _otlpEndpoint }, "OTLP telemetry ingestion active");
|
|
18595
18032
|
} catch {}
|
|
18596
18033
|
}
|
|
18597
18034
|
const interfaceContractDecisions = await getDecisionsByCategory(db, "interface-contract");
|
|
@@ -18617,12 +18054,12 @@ function createImplementationOrchestrator(deps) {
|
|
|
18617
18054
|
const conflictDetectStart = Date.now();
|
|
18618
18055
|
const { batches, edges: contractEdges } = detectConflictGroupsWithContracts(storyKeys, { moduleMap: pack.manifest.conflictGroups }, contractDeclarations);
|
|
18619
18056
|
_startupTimings.conflictDetectMs = Date.now() - conflictDetectStart;
|
|
18620
|
-
if (contractEdges.length > 0) logger$
|
|
18057
|
+
if (contractEdges.length > 0) logger$26.info({
|
|
18621
18058
|
contractEdges,
|
|
18622
18059
|
edgeCount: contractEdges.length
|
|
18623
18060
|
}, "Contract dependency edges detected — applying contract-aware dispatch ordering");
|
|
18624
|
-
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$
|
|
18625
|
-
logger$
|
|
18061
|
+
wgRepo.addContractDependencies(contractEdges).catch((err) => logger$26.warn({ err }, "contract dep persistence failed (best-effort)"));
|
|
18062
|
+
logger$26.info({
|
|
18626
18063
|
storyCount: storyKeys.length,
|
|
18627
18064
|
groupCount: batches.reduce((sum, b) => sum + b.length, 0),
|
|
18628
18065
|
batchCount: batches.length,
|
|
@@ -18632,7 +18069,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18632
18069
|
groups: batch.map((g) => g.join(","))
|
|
18633
18070
|
}))
|
|
18634
18071
|
}, "Orchestrator starting");
|
|
18635
|
-
logger$
|
|
18072
|
+
logger$26.info({
|
|
18636
18073
|
storyCount: storyKeys.length,
|
|
18637
18074
|
conflictGroups: batches.length,
|
|
18638
18075
|
maxConcurrency: config.maxConcurrency
|
|
@@ -18653,7 +18090,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18653
18090
|
exitCode,
|
|
18654
18091
|
output: truncatedOutput
|
|
18655
18092
|
});
|
|
18656
|
-
logger$
|
|
18093
|
+
logger$26.error({
|
|
18657
18094
|
exitCode,
|
|
18658
18095
|
reason: preFlightResult.reason
|
|
18659
18096
|
}, "Pre-flight build check failed — aborting pipeline before any story dispatch");
|
|
@@ -18662,19 +18099,19 @@ function createImplementationOrchestrator(deps) {
|
|
|
18662
18099
|
await persistState();
|
|
18663
18100
|
return getStatus();
|
|
18664
18101
|
}
|
|
18665
|
-
if (preFlightResult.status !== "skipped") logger$
|
|
18102
|
+
if (preFlightResult.status !== "skipped") logger$26.info("Pre-flight build check passed");
|
|
18666
18103
|
}
|
|
18667
|
-
logger$
|
|
18104
|
+
logger$26.info(_startupTimings, "Orchestrator startup timings (ms)");
|
|
18668
18105
|
const totalGroups = batches.reduce((sum, b) => sum + b.length, 0);
|
|
18669
18106
|
const actualConcurrency = Math.min(config.maxConcurrency, totalGroups);
|
|
18670
18107
|
if (actualConcurrency > 1 && projectRoot !== void 0) try {
|
|
18671
18108
|
_packageSnapshot = capturePackageSnapshot({ projectRoot });
|
|
18672
|
-
logger$
|
|
18109
|
+
logger$26.info({
|
|
18673
18110
|
fileCount: _packageSnapshot.files.size,
|
|
18674
18111
|
installCommand: _packageSnapshot.installCommand
|
|
18675
18112
|
}, "Package snapshot captured for concurrent story protection");
|
|
18676
18113
|
} catch (snapErr) {
|
|
18677
|
-
logger$
|
|
18114
|
+
logger$26.warn({ err: snapErr }, "Failed to capture package snapshot — continuing without protection");
|
|
18678
18115
|
}
|
|
18679
18116
|
try {
|
|
18680
18117
|
for (const rawBatchGroups of batches) {
|
|
@@ -18699,14 +18136,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
18699
18136
|
manifest: runManifest,
|
|
18700
18137
|
adapter: db
|
|
18701
18138
|
});
|
|
18702
|
-
if (!recoveryResult.noStale) logger$
|
|
18139
|
+
if (!recoveryResult.noStale) logger$26.info({
|
|
18703
18140
|
recovered: recoveryResult.recovered,
|
|
18704
18141
|
stillFailed: recoveryResult.stillFailed,
|
|
18705
18142
|
recoveredCount: recoveryResult.recovered.length,
|
|
18706
18143
|
stillFailedCount: recoveryResult.stillFailed.length
|
|
18707
18144
|
}, "Cross-story race recovery complete");
|
|
18708
18145
|
} catch (recoveryErr) {
|
|
18709
|
-
logger$
|
|
18146
|
+
logger$26.warn({ err: recoveryErr }, "Cross-story race recovery failed (non-fatal) — pipeline continues");
|
|
18710
18147
|
}
|
|
18711
18148
|
}
|
|
18712
18149
|
}
|
|
@@ -18715,7 +18152,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18715
18152
|
_state = "FAILED";
|
|
18716
18153
|
_completedAt = new Date().toISOString();
|
|
18717
18154
|
await persistState();
|
|
18718
|
-
logger$
|
|
18155
|
+
logger$26.error({ err }, "Orchestrator failed with unhandled error");
|
|
18719
18156
|
return getStatus();
|
|
18720
18157
|
}
|
|
18721
18158
|
stopHeartbeat();
|
|
@@ -18725,7 +18162,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18725
18162
|
const totalDeclarations = contractDeclarations.length;
|
|
18726
18163
|
const currentSprintDeclarations = contractDeclarations.filter((d) => storyKeys.includes(d.storyKey));
|
|
18727
18164
|
const stalePruned = totalDeclarations - currentSprintDeclarations.length;
|
|
18728
|
-
if (stalePruned > 0) logger$
|
|
18165
|
+
if (stalePruned > 0) logger$26.info({
|
|
18729
18166
|
stalePruned,
|
|
18730
18167
|
remaining: currentSprintDeclarations.length
|
|
18731
18168
|
}, "Pruned stale contract declarations from previous epics");
|
|
@@ -18739,11 +18176,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
18739
18176
|
contractName: mismatch.contractName,
|
|
18740
18177
|
mismatchDescription: mismatch.mismatchDescription
|
|
18741
18178
|
});
|
|
18742
|
-
logger$
|
|
18179
|
+
logger$26.warn({
|
|
18743
18180
|
mismatchCount: mismatches.length,
|
|
18744
18181
|
mismatches
|
|
18745
18182
|
}, "Post-sprint contract verification found mismatches — manual review required");
|
|
18746
|
-
} else if (currentSprintDeclarations.length > 0) logger$
|
|
18183
|
+
} else if (currentSprintDeclarations.length > 0) logger$26.info("Post-sprint contract verification passed — all declared contracts satisfied");
|
|
18747
18184
|
eventBus.emit("pipeline:contract-verification-summary", {
|
|
18748
18185
|
verified: currentSprintDeclarations.length,
|
|
18749
18186
|
stalePruned,
|
|
@@ -18751,7 +18188,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18751
18188
|
verdict: mismatches.length === 0 ? "pass" : "fail"
|
|
18752
18189
|
});
|
|
18753
18190
|
} catch (err) {
|
|
18754
|
-
logger$
|
|
18191
|
+
logger$26.error({ err }, "Post-sprint contract verification threw an error — skipping");
|
|
18755
18192
|
}
|
|
18756
18193
|
if (projectRoot !== void 0) try {
|
|
18757
18194
|
const indicators = checkProfileStaleness(projectRoot);
|
|
@@ -18761,15 +18198,26 @@ function createImplementationOrchestrator(deps) {
|
|
|
18761
18198
|
message,
|
|
18762
18199
|
indicators
|
|
18763
18200
|
});
|
|
18764
|
-
logger$
|
|
18201
|
+
logger$26.warn({ indicators }, message);
|
|
18765
18202
|
}
|
|
18766
18203
|
} catch (err) {
|
|
18767
|
-
logger$
|
|
18204
|
+
logger$26.debug({ err }, "Profile staleness check failed (best-effort)");
|
|
18768
18205
|
}
|
|
18769
18206
|
try {
|
|
18770
|
-
await auditJourneyCoverage({ final: true }, { persist: true });
|
|
18207
|
+
const finalAudit = await auditJourneyCoverage({ final: true }, { persist: true });
|
|
18208
|
+
if (resolveAcceptanceMode() === "blocking" && finalAudit !== void 0) {
|
|
18209
|
+
const criticalViolations = finalAudit.entries.filter((e) => e.criticality === "critical" && (e.state === "unclaimed" || e.state === "unwalked" || e.state === "walked-fail"));
|
|
18210
|
+
if (criticalViolations.length > 0) {
|
|
18211
|
+
const msg = `acceptance-coverage-violation (run end): ${String(criticalViolations.length)} journey-critical violation(s) survived to run end — ` + criticalViolations.map((v) => `${v.journeyId} [${v.state}]`).join(", ") + ". In blocking mode these should have been caught at epic close; a residual here indicates a concurrency race or an epic that never formally closed. Inspect the coverage ledger in `substrate report`.";
|
|
18212
|
+
logger$26.error({ criticalViolations: criticalViolations.map((v) => v.journeyId) }, msg);
|
|
18213
|
+
eventBus.emit("orchestrator:story-warn", {
|
|
18214
|
+
storyKey: "(run)",
|
|
18215
|
+
msg
|
|
18216
|
+
});
|
|
18217
|
+
}
|
|
18218
|
+
}
|
|
18771
18219
|
} catch (err) {
|
|
18772
|
-
logger$
|
|
18220
|
+
logger$26.warn({ err }, "A0.3: run-end coverage sweep failed (best-effort)");
|
|
18773
18221
|
}
|
|
18774
18222
|
let completed = 0;
|
|
18775
18223
|
let escalated = 0;
|
|
@@ -18788,7 +18236,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18788
18236
|
} finally {
|
|
18789
18237
|
process.off("SIGTERM", sigtermHandler);
|
|
18790
18238
|
process.off("SIGINT", sigintHandler);
|
|
18791
|
-
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$
|
|
18239
|
+
if (ingestionServer !== void 0) await ingestionServer.stop().catch((err) => logger$26.warn({ err }, "IngestionServer.stop() failed (best-effort)"));
|
|
18792
18240
|
}
|
|
18793
18241
|
}
|
|
18794
18242
|
function pause() {
|
|
@@ -18797,7 +18245,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18797
18245
|
_pauseGate = createPauseGate();
|
|
18798
18246
|
_state = "PAUSED";
|
|
18799
18247
|
eventBus.emit("orchestrator:paused", {});
|
|
18800
|
-
logger$
|
|
18248
|
+
logger$26.info("Orchestrator paused");
|
|
18801
18249
|
}
|
|
18802
18250
|
function resume() {
|
|
18803
18251
|
if (_state !== "PAUSED") return;
|
|
@@ -18808,7 +18256,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
18808
18256
|
}
|
|
18809
18257
|
_state = "RUNNING";
|
|
18810
18258
|
eventBus.emit("orchestrator:resumed", {});
|
|
18811
|
-
logger$
|
|
18259
|
+
logger$26.info("Orchestrator resumed");
|
|
18812
18260
|
}
|
|
18813
18261
|
return {
|
|
18814
18262
|
run,
|
|
@@ -35900,16 +35348,16 @@ var require_ajv = __commonJS({ "node_modules/ajv/lib/ajv.js"(exports, module) {
|
|
|
35900
35348
|
return metaOpts;
|
|
35901
35349
|
}
|
|
35902
35350
|
function setLogger(self) {
|
|
35903
|
-
var logger$
|
|
35904
|
-
if (logger$
|
|
35351
|
+
var logger$26 = self._opts.logger;
|
|
35352
|
+
if (logger$26 === false) self.logger = {
|
|
35905
35353
|
log: noop,
|
|
35906
35354
|
warn: noop,
|
|
35907
35355
|
error: noop
|
|
35908
35356
|
};
|
|
35909
35357
|
else {
|
|
35910
|
-
if (logger$
|
|
35911
|
-
if (!(typeof logger$
|
|
35912
|
-
self.logger = logger$
|
|
35358
|
+
if (logger$26 === void 0) logger$26 = console;
|
|
35359
|
+
if (!(typeof logger$26 == "object" && logger$26.log && logger$26.warn && logger$26.error)) throw new Error("logger must implement log, warn and error methods");
|
|
35360
|
+
self.logger = logger$26;
|
|
35913
35361
|
}
|
|
35914
35362
|
}
|
|
35915
35363
|
function noop() {}
|
|
@@ -48802,7 +48250,7 @@ async function runFullPipeline(options) {
|
|
|
48802
48250
|
*/
|
|
48803
48251
|
async function emitPreDispatchVersionAdvisory(currentVersion) {
|
|
48804
48252
|
if (process.env["SUBSTRATE_NO_UPDATE_CHECK"] === "1") return;
|
|
48805
|
-
const { createVersionManager } = await import("./version-manager-impl-
|
|
48253
|
+
const { createVersionManager } = await import("./version-manager-impl-B9VDdCKb.js");
|
|
48806
48254
|
const vm = createVersionManager();
|
|
48807
48255
|
const result = await vm.checkForUpdates(true);
|
|
48808
48256
|
const gap = classifyVersionGap(currentVersion, result.latestVersion);
|
|
@@ -48908,5 +48356,5 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
|
|
|
48908
48356
|
}
|
|
48909
48357
|
|
|
48910
48358
|
//#endregion
|
|
48911
|
-
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys,
|
|
48912
|
-
//# sourceMappingURL=run-
|
|
48359
|
+
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
48360
|
+
//# sourceMappingURL=run-CoZ5kK6c.js.map
|