harness-engineering-agent 0.3.10 → 0.3.12

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.
Files changed (177) hide show
  1. package/README.md +4 -0
  2. package/dist/controller/agent-session-types.d.ts +17 -1
  3. package/dist/controller/agent-session-types.d.ts.map +1 -1
  4. package/dist/controller/agent-session-utils.d.ts +40 -3
  5. package/dist/controller/agent-session-utils.d.ts.map +1 -1
  6. package/dist/controller/agent-session-utils.js +67 -21
  7. package/dist/controller/agent-session-utils.js.map +1 -1
  8. package/dist/controller/agent-session.d.ts.map +1 -1
  9. package/dist/controller/agent-session.js +129 -10
  10. package/dist/controller/agent-session.js.map +1 -1
  11. package/dist/controller/context-budget.d.ts +71 -0
  12. package/dist/controller/context-budget.d.ts.map +1 -0
  13. package/dist/controller/context-budget.js +219 -0
  14. package/dist/controller/context-budget.js.map +1 -0
  15. package/dist/controller/context-builder.d.ts +27 -0
  16. package/dist/controller/context-builder.d.ts.map +1 -0
  17. package/dist/controller/context-builder.js +184 -0
  18. package/dist/controller/context-builder.js.map +1 -0
  19. package/dist/controller/context-validation.d.ts +46 -0
  20. package/dist/controller/context-validation.d.ts.map +1 -0
  21. package/dist/controller/context-validation.js +126 -0
  22. package/dist/controller/context-validation.js.map +1 -0
  23. package/dist/controller/direct-runner.d.ts +2 -0
  24. package/dist/controller/direct-runner.d.ts.map +1 -1
  25. package/dist/controller/direct-runner.js +20 -2
  26. package/dist/controller/direct-runner.js.map +1 -1
  27. package/dist/controller/evidence-factory.d.ts +2 -1
  28. package/dist/controller/evidence-factory.d.ts.map +1 -1
  29. package/dist/controller/evidence-factory.js +1 -0
  30. package/dist/controller/evidence-factory.js.map +1 -1
  31. package/dist/controller/failure-analysis.d.ts.map +1 -1
  32. package/dist/controller/failure-analysis.js +18 -0
  33. package/dist/controller/failure-analysis.js.map +1 -1
  34. package/dist/controller/graph-validator.d.ts.map +1 -1
  35. package/dist/controller/graph-validator.js +25 -0
  36. package/dist/controller/graph-validator.js.map +1 -1
  37. package/dist/controller/index.d.ts +1 -0
  38. package/dist/controller/index.d.ts.map +1 -1
  39. package/dist/controller/index.js +1 -0
  40. package/dist/controller/index.js.map +1 -1
  41. package/dist/controller/repair-loop.d.ts.map +1 -1
  42. package/dist/controller/repair-loop.js +1 -0
  43. package/dist/controller/repair-loop.js.map +1 -1
  44. package/dist/controller/report-factory.d.ts.map +1 -1
  45. package/dist/controller/report-factory.js +8 -0
  46. package/dist/controller/report-factory.js.map +1 -1
  47. package/dist/controller/run-acceptance.d.ts.map +1 -1
  48. package/dist/controller/run-acceptance.js +22 -1
  49. package/dist/controller/run-acceptance.js.map +1 -1
  50. package/dist/controller/run-controller.d.ts.map +1 -1
  51. package/dist/controller/run-controller.js +16 -112
  52. package/dist/controller/run-controller.js.map +1 -1
  53. package/dist/controller/run-error-finalizer.d.ts +14 -0
  54. package/dist/controller/run-error-finalizer.d.ts.map +1 -0
  55. package/dist/controller/run-error-finalizer.js +56 -0
  56. package/dist/controller/run-error-finalizer.js.map +1 -0
  57. package/dist/controller/run-reflection.d.ts +13 -0
  58. package/dist/controller/run-reflection.d.ts.map +1 -0
  59. package/dist/controller/run-reflection.js +27 -0
  60. package/dist/controller/run-reflection.js.map +1 -0
  61. package/dist/controller/run-workspace.d.ts +16 -0
  62. package/dist/controller/run-workspace.d.ts.map +1 -0
  63. package/dist/controller/run-workspace.js +43 -0
  64. package/dist/controller/run-workspace.js.map +1 -0
  65. package/dist/controller/streamlined-runner.d.ts +2 -0
  66. package/dist/controller/streamlined-runner.d.ts.map +1 -1
  67. package/dist/controller/streamlined-runner.js +31 -1
  68. package/dist/controller/streamlined-runner.js.map +1 -1
  69. package/dist/controller/task-agent-output.d.ts.map +1 -1
  70. package/dist/controller/task-agent-output.js +90 -0
  71. package/dist/controller/task-agent-output.js.map +1 -1
  72. package/dist/controller/task-agent-schemas.d.ts +16 -2
  73. package/dist/controller/task-agent-schemas.d.ts.map +1 -1
  74. package/dist/controller/task-agent-schemas.js +2 -1
  75. package/dist/controller/task-agent-schemas.js.map +1 -1
  76. package/dist/controller/task-executor.d.ts.map +1 -1
  77. package/dist/controller/task-executor.js +25 -2
  78. package/dist/controller/task-executor.js.map +1 -1
  79. package/dist/domain/agent-result.d.ts +4 -0
  80. package/dist/domain/agent-result.d.ts.map +1 -1
  81. package/dist/domain/agent-result.js +2 -1
  82. package/dist/domain/agent-result.js.map +1 -1
  83. package/dist/domain/clarification.d.ts +92 -0
  84. package/dist/domain/clarification.d.ts.map +1 -0
  85. package/dist/domain/clarification.js +80 -0
  86. package/dist/domain/clarification.js.map +1 -0
  87. package/dist/domain/context-snapshot.d.ts +140 -0
  88. package/dist/domain/context-snapshot.d.ts.map +1 -0
  89. package/dist/domain/context-snapshot.js +140 -0
  90. package/dist/domain/context-snapshot.js.map +1 -0
  91. package/dist/domain/evidence.d.ts +1 -0
  92. package/dist/domain/evidence.d.ts.map +1 -1
  93. package/dist/domain/evidence.js +2 -1
  94. package/dist/domain/evidence.js.map +1 -1
  95. package/dist/domain/index.d.ts +6 -2
  96. package/dist/domain/index.d.ts.map +1 -1
  97. package/dist/domain/index.js +3 -1
  98. package/dist/domain/index.js.map +1 -1
  99. package/dist/domain/plan-artifacts.d.ts +4 -1
  100. package/dist/domain/plan-artifacts.d.ts.map +1 -1
  101. package/dist/domain/report.d.ts +166 -7
  102. package/dist/domain/report.d.ts.map +1 -1
  103. package/dist/domain/report.js +7 -1
  104. package/dist/domain/report.js.map +1 -1
  105. package/dist/domain/requirement.d.ts +3 -0
  106. package/dist/domain/requirement.d.ts.map +1 -1
  107. package/dist/domain/requirement.js +6 -1
  108. package/dist/domain/requirement.js.map +1 -1
  109. package/dist/domain/run-acceptance.d.ts +1 -0
  110. package/dist/domain/run-acceptance.d.ts.map +1 -1
  111. package/dist/domain/run-acceptance.js +2 -1
  112. package/dist/domain/run-acceptance.js.map +1 -1
  113. package/dist/domain/run.d.ts +153 -7
  114. package/dist/domain/run.d.ts.map +1 -1
  115. package/dist/domain/run.js +28 -1
  116. package/dist/domain/run.js.map +1 -1
  117. package/dist/domain/shared.d.ts +6 -4
  118. package/dist/domain/shared.d.ts.map +1 -1
  119. package/dist/domain/shared.js +1 -0
  120. package/dist/domain/shared.js.map +1 -1
  121. package/dist/domain/task-review.d.ts +1 -0
  122. package/dist/domain/task-review.d.ts.map +1 -1
  123. package/dist/domain/task-review.js +2 -1
  124. package/dist/domain/task-review.js.map +1 -1
  125. package/dist/domain/task.d.ts +6 -2
  126. package/dist/domain/task.d.ts.map +1 -1
  127. package/dist/domain/task.js +4 -1
  128. package/dist/domain/task.js.map +1 -1
  129. package/dist/plugin/harness-chat-hook.d.ts +2 -0
  130. package/dist/plugin/harness-chat-hook.d.ts.map +1 -1
  131. package/dist/plugin/harness-chat-hook.js +31 -17
  132. package/dist/plugin/harness-chat-hook.js.map +1 -1
  133. package/dist/plugin/harness-coordinator.d.ts +5 -0
  134. package/dist/plugin/harness-coordinator.d.ts.map +1 -1
  135. package/dist/plugin/harness-coordinator.js +115 -6
  136. package/dist/plugin/harness-coordinator.js.map +1 -1
  137. package/dist/plugin/harness-intake-prompt.d.ts.map +1 -1
  138. package/dist/plugin/harness-intake-prompt.js +3 -3
  139. package/dist/plugin/harness-intake-prompt.js.map +1 -1
  140. package/dist/plugin/harness-plugin-runtime.d.ts +3 -18
  141. package/dist/plugin/harness-plugin-runtime.d.ts.map +1 -1
  142. package/dist/plugin/harness-plugin-runtime.js +9 -1
  143. package/dist/plugin/harness-plugin-runtime.js.map +1 -1
  144. package/dist/session/contracts.d.ts +80 -8
  145. package/dist/session/contracts.d.ts.map +1 -1
  146. package/dist/session/fake-session-adapter.d.ts.map +1 -1
  147. package/dist/session/fake-session-adapter.js +14 -0
  148. package/dist/session/fake-session-adapter.js.map +1 -1
  149. package/dist/session/opencode-session-adapter.d.ts.map +1 -1
  150. package/dist/session/opencode-session-adapter.js +16 -0
  151. package/dist/session/opencode-session-adapter.js.map +1 -1
  152. package/dist/session/opencode-session-prompts.d.ts.map +1 -1
  153. package/dist/session/opencode-session-prompts.js +3 -0
  154. package/dist/session/opencode-session-prompts.js.map +1 -1
  155. package/dist/store/context-snapshot-store.d.ts +17 -0
  156. package/dist/store/context-snapshot-store.d.ts.map +1 -0
  157. package/dist/store/context-snapshot-store.js +96 -0
  158. package/dist/store/context-snapshot-store.js.map +1 -0
  159. package/dist/store/filesystem-run-store.d.ts +3 -0
  160. package/dist/store/filesystem-run-store.d.ts.map +1 -1
  161. package/dist/store/filesystem-run-store.js +13 -1
  162. package/dist/store/filesystem-run-store.js.map +1 -1
  163. package/dist/store/index.d.ts +2 -0
  164. package/dist/store/index.d.ts.map +1 -1
  165. package/dist/store/index.js +2 -0
  166. package/dist/store/index.js.map +1 -1
  167. package/dist/store/run-event.d.ts +153 -7
  168. package/dist/store/run-event.d.ts.map +1 -1
  169. package/dist/store/session-index.d.ts +51 -0
  170. package/dist/store/session-index.d.ts.map +1 -0
  171. package/dist/store/session-index.js +163 -0
  172. package/dist/store/session-index.js.map +1 -0
  173. package/dist/workspace/git-baseline.d.ts +1 -0
  174. package/dist/workspace/git-baseline.d.ts.map +1 -1
  175. package/dist/workspace/git-baseline.js +2 -0
  176. package/dist/workspace/git-baseline.js.map +1 -1
  177. package/package.json +1 -1
@@ -0,0 +1,71 @@
1
+ import type { ContextFact, ContextSnapshot, ContextSummary } from "../domain/context-snapshot.js";
2
+ import type { HarnessSessionRole } from "../session/contracts.js";
3
+ export type ContextBudget = {
4
+ /** Maximum number of facts to include */
5
+ readonly maxFacts: number;
6
+ /** Maximum number of evidence digests to include */
7
+ readonly maxEvidenceDigests: number;
8
+ /** Maximum number of unresolved issues to include */
9
+ readonly maxUnresolvedIssues: number;
10
+ /** Maximum character length for the goal text */
11
+ readonly maxGoalLength: number;
12
+ /** Maximum character length for the scope text */
13
+ readonly maxScopeLength: number;
14
+ };
15
+ /**
16
+ * Default per-role context budgets.
17
+ *
18
+ * FIXME: These values are reasonable defaults for the current Harness
19
+ * architecture but should be made configurable via project-level
20
+ * configuration (e.g. .harness/config.yaml) in a future iteration.
21
+ * The current thresholds are designed to keep session prompts under
22
+ * typical provider token limits while preserving the most critical
23
+ * context for each role.
24
+ */
25
+ export declare const DEFAULT_ROLE_BUDGETS: Record<HarnessSessionRole, ContextBudget>;
26
+ export type TrimmedContext = {
27
+ /** The trimmed context snapshot */
28
+ readonly snapshot: ContextSnapshot;
29
+ /** Summary of the context for lightweight reference */
30
+ readonly summary: ContextSummary;
31
+ /** Which facts were trimmed (by factId) */
32
+ readonly trimmedFactIds: readonly string[];
33
+ /** Which evidence digests were trimmed (by refId) */
34
+ readonly trimmedEvidenceRefIds: readonly string[];
35
+ /** Which unresolved issues were trimmed */
36
+ readonly trimmedUnresolvedIssues: readonly string[];
37
+ /** Fingerprint of the trimmed content */
38
+ readonly trimDigest: string;
39
+ /** Whether any trimming was applied */
40
+ readonly wasTrimmed: boolean;
41
+ };
42
+ /**
43
+ * Trim a context snapshot to fit within a role's budget.
44
+ *
45
+ * This function NEVER truncates text arbitrarily. Instead, it uses
46
+ * structured strategies in order:
47
+ * 1. Keep all high-priority facts (priority >= 80): goals, constraints,
48
+ * allowed paths, acceptance criteria, blocking issues.
49
+ * 2. For remaining lower-priority facts, keep the most recent/highest-priority
50
+ * ones up to the budget.
51
+ * 3. Trim evidence digests to the budget limit.
52
+ * 4. Trim unresolved issues to the budget limit.
53
+ * 5. Truncate goal/scope text to character limits.
54
+ *
55
+ * Excess content is recorded in trim metadata for auditability.
56
+ */
57
+ export declare const trimContextForRole: (snapshot: ContextSnapshot, role: HarnessSessionRole, budget?: ContextBudget) => TrimmedContext;
58
+ /**
59
+ * Context layers that can be selectively included per role.
60
+ */
61
+ export type ContextLayer = "fixed_role" | "run" | "task" | "evidence" | "governance";
62
+ /**
63
+ * Which layers each role receives by default.
64
+ */
65
+ export declare const DEFAULT_ROLE_LAYERS: Record<HarnessSessionRole, readonly ContextLayer[]>;
66
+ /**
67
+ * Filter facts by layer, keeping only those whose kind matches the
68
+ * requested layers.
69
+ */
70
+ export declare const filterFactsByLayer: (facts: readonly ContextFact[], layers: readonly ContextLayer[]) => readonly ContextFact[];
71
+ //# sourceMappingURL=context-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.d.ts","sourceRoot":"","sources":["../../src/controller/context-budget.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEjG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,MAAM,aAAa,GAAG;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,oDAAoD;IACpD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,qDAAqD;IACrD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,iDAAiD;IACjD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,kBAAkB,EAAE,aAAa,CAkD1E,CAAA;AAID,MAAM,MAAM,cAAc,GAAG;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,qDAAqD;IACrD,QAAQ,CAAC,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAA;IACjD,2CAA2C;IAC3C,QAAQ,CAAC,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAA;IACnD,yCAAyC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAC7B,CAAA;AAaD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,eAAe,EACzB,MAAM,kBAAkB,EACxB,SAAS,aAAa,KACrB,cA6EF,CAAA;AA2CD;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,KAAK,GACL,MAAM,GACN,UAAU,GACV,YAAY,CAAA;AAEhB;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,kBAAkB,EAAE,SAAS,YAAY,EAAE,CAQnF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,SAAS,WAAW,EAAE,EAC7B,QAAQ,SAAS,YAAY,EAAE,KAC9B,SAAS,WAAW,EAmBtB,CAAA"}
@@ -0,0 +1,219 @@
1
+ import { createHash } from "node:crypto";
2
+ import { toContextSummary } from "../domain/context-snapshot.js";
3
+ import { HARNESS_SESSION_ROLE } from "../session/contracts.js";
4
+ /**
5
+ * Default per-role context budgets.
6
+ *
7
+ * FIXME: These values are reasonable defaults for the current Harness
8
+ * architecture but should be made configurable via project-level
9
+ * configuration (e.g. .harness/config.yaml) in a future iteration.
10
+ * The current thresholds are designed to keep session prompts under
11
+ * typical provider token limits while preserving the most critical
12
+ * context for each role.
13
+ */
14
+ export const DEFAULT_ROLE_BUDGETS = {
15
+ [HARNESS_SESSION_ROLE.intake]: {
16
+ maxFacts: 30,
17
+ maxEvidenceDigests: 0,
18
+ maxUnresolvedIssues: 5,
19
+ maxGoalLength: 1000,
20
+ maxScopeLength: 2000,
21
+ },
22
+ [HARNESS_SESSION_ROLE.planner]: {
23
+ maxFacts: 50,
24
+ maxEvidenceDigests: 10,
25
+ maxUnresolvedIssues: 10,
26
+ maxGoalLength: 2000,
27
+ maxScopeLength: 4000,
28
+ },
29
+ [HARNESS_SESSION_ROLE.worker]: {
30
+ maxFacts: 40,
31
+ maxEvidenceDigests: 15,
32
+ maxUnresolvedIssues: 5,
33
+ maxGoalLength: 1500,
34
+ maxScopeLength: 3000,
35
+ },
36
+ [HARNESS_SESSION_ROLE.verifier]: {
37
+ maxFacts: 30,
38
+ maxEvidenceDigests: 20,
39
+ maxUnresolvedIssues: 5,
40
+ maxGoalLength: 1000,
41
+ maxScopeLength: 2000,
42
+ },
43
+ [HARNESS_SESSION_ROLE.acceptance]: {
44
+ maxFacts: 30,
45
+ maxEvidenceDigests: 20,
46
+ maxUnresolvedIssues: 5,
47
+ maxGoalLength: 1000,
48
+ maxScopeLength: 2000,
49
+ },
50
+ [HARNESS_SESSION_ROLE.failureAnalyzer]: {
51
+ maxFacts: 40,
52
+ maxEvidenceDigests: 15,
53
+ maxUnresolvedIssues: 10,
54
+ maxGoalLength: 1500,
55
+ maxScopeLength: 3000,
56
+ },
57
+ [HARNESS_SESSION_ROLE.repairWorker]: {
58
+ maxFacts: 40,
59
+ maxEvidenceDigests: 15,
60
+ maxUnresolvedIssues: 5,
61
+ maxGoalLength: 1500,
62
+ maxScopeLength: 3000,
63
+ },
64
+ };
65
+ // ─── Priority constants ────────────────────────────────────────────────────
66
+ /**
67
+ * Facts with priority >= HIGH_PRIORITY_THRESHOLD are considered
68
+ * "must-preserve" — they include goals, constraints, allowed paths,
69
+ * acceptance criteria, and blocking issues.
70
+ */
71
+ const HIGH_PRIORITY_THRESHOLD = 80;
72
+ // ─── Trimming function ─────────────────────────────────────────────────────
73
+ /**
74
+ * Trim a context snapshot to fit within a role's budget.
75
+ *
76
+ * This function NEVER truncates text arbitrarily. Instead, it uses
77
+ * structured strategies in order:
78
+ * 1. Keep all high-priority facts (priority >= 80): goals, constraints,
79
+ * allowed paths, acceptance criteria, blocking issues.
80
+ * 2. For remaining lower-priority facts, keep the most recent/highest-priority
81
+ * ones up to the budget.
82
+ * 3. Trim evidence digests to the budget limit.
83
+ * 4. Trim unresolved issues to the budget limit.
84
+ * 5. Truncate goal/scope text to character limits.
85
+ *
86
+ * Excess content is recorded in trim metadata for auditability.
87
+ */
88
+ export const trimContextForRole = (snapshot, role, budget) => {
89
+ const effectiveBudget = budget ?? DEFAULT_ROLE_BUDGETS[role];
90
+ const trimmedFactIds = [];
91
+ const trimmedEvidenceRefIds = [];
92
+ const trimmedUnresolvedIssues = [];
93
+ let wasTrimmed = false;
94
+ // ── 1. Priority-based fact trimming ──
95
+ const sortedFacts = [...snapshot.facts].sort((a, b) => b.priority - a.priority);
96
+ const highPriority = sortedFacts.filter((f) => f.priority >= HIGH_PRIORITY_THRESHOLD);
97
+ const lowPriority = sortedFacts.filter((f) => f.priority < HIGH_PRIORITY_THRESHOLD);
98
+ // Always keep high-priority facts
99
+ const remainingBudget = effectiveBudget.maxFacts - highPriority.length;
100
+ const keptLowPriority = lowPriority.slice(0, Math.max(0, remainingBudget));
101
+ const trimmedLowPriority = lowPriority.slice(Math.max(0, remainingBudget));
102
+ for (const fact of trimmedLowPriority) {
103
+ trimmedFactIds.push(fact.factId);
104
+ }
105
+ const keptFacts = [...highPriority, ...keptLowPriority];
106
+ // ── 2. Evidence digest trimming ──
107
+ const keptEvidenceDigests = snapshot.evidenceDigests.slice(0, effectiveBudget.maxEvidenceDigests);
108
+ const trimmedEvidence = snapshot.evidenceDigests.slice(effectiveBudget.maxEvidenceDigests);
109
+ for (const ev of trimmedEvidence) {
110
+ trimmedEvidenceRefIds.push(ev.refId);
111
+ }
112
+ // ── 3. Unresolved issues trimming ──
113
+ const keptIssues = snapshot.unresolvedIssues.slice(0, effectiveBudget.maxUnresolvedIssues);
114
+ const trimmedIssues = snapshot.unresolvedIssues.slice(effectiveBudget.maxUnresolvedIssues);
115
+ trimmedUnresolvedIssues.push(...trimmedIssues);
116
+ // ── 4. Text truncation for goal/scope ──
117
+ // Ensure we don't cut mid-word or mid-JSON — truncate at word boundary
118
+ const truncatedGoal = truncateAtWordBoundary(snapshot.goal, effectiveBudget.maxGoalLength);
119
+ const truncatedScope = truncateAtWordBoundary(snapshot.scope, effectiveBudget.maxScopeLength);
120
+ wasTrimmed =
121
+ trimmedFactIds.length > 0 ||
122
+ trimmedEvidenceRefIds.length > 0 ||
123
+ trimmedUnresolvedIssues.length > 0 ||
124
+ truncatedGoal !== snapshot.goal ||
125
+ truncatedScope !== snapshot.scope;
126
+ // ── Build trimmed snapshot ──
127
+ const trimDigest = computeTrimDigest({
128
+ trimmedFactIds,
129
+ trimmedEvidenceRefIds,
130
+ trimmedUnresolvedIssues,
131
+ budget: effectiveBudget,
132
+ role,
133
+ });
134
+ const trimmedSnapshot = {
135
+ ...snapshot,
136
+ goal: truncatedGoal,
137
+ scope: truncatedScope,
138
+ // Keep facts sorted by priority for the agent
139
+ facts: keptFacts.sort((a, b) => b.priority - a.priority),
140
+ evidenceDigests: keptEvidenceDigests,
141
+ unresolvedIssues: keptIssues,
142
+ };
143
+ const summary = toContextSummary(trimmedSnapshot);
144
+ return {
145
+ snapshot: trimmedSnapshot,
146
+ summary,
147
+ trimmedFactIds,
148
+ trimmedEvidenceRefIds,
149
+ trimmedUnresolvedIssues,
150
+ trimDigest,
151
+ wasTrimmed,
152
+ };
153
+ };
154
+ // ─── Helpers ───────────────────────────────────────────────────────────────
155
+ /**
156
+ * Truncate text at a word boundary, ensuring we never cut mid-word
157
+ * or mid-JSON structure. Appends "…" if truncated.
158
+ */
159
+ const truncateAtWordBoundary = (text, maxLength) => {
160
+ if (text.length <= maxLength)
161
+ return text;
162
+ // Try to find the last space within the limit
163
+ let cutIndex = maxLength;
164
+ const lastSpace = text.lastIndexOf(" ", maxLength);
165
+ if (lastSpace > maxLength / 2) {
166
+ cutIndex = lastSpace;
167
+ }
168
+ return `${text.slice(0, cutIndex).trimEnd()}…`;
169
+ };
170
+ /**
171
+ * Compute a deterministic digest of the trimming metadata.
172
+ */
173
+ const computeTrimDigest = (input) => {
174
+ const canonical = JSON.stringify({
175
+ trimmedFactIds: input.trimmedFactIds,
176
+ trimmedEvidenceRefIds: input.trimmedEvidenceRefIds,
177
+ trimmedUnresolvedIssues: input.trimmedUnresolvedIssues,
178
+ budget: input.budget,
179
+ role: input.role,
180
+ });
181
+ return `sha256:${createHash("sha256").update(canonical, "utf8").digest("hex")}`;
182
+ };
183
+ /**
184
+ * Which layers each role receives by default.
185
+ */
186
+ export const DEFAULT_ROLE_LAYERS = {
187
+ [HARNESS_SESSION_ROLE.intake]: ["fixed_role", "run"],
188
+ [HARNESS_SESSION_ROLE.planner]: ["fixed_role", "run", "governance"],
189
+ [HARNESS_SESSION_ROLE.worker]: ["fixed_role", "run", "task", "evidence"],
190
+ [HARNESS_SESSION_ROLE.verifier]: ["fixed_role", "run", "task", "evidence"],
191
+ [HARNESS_SESSION_ROLE.acceptance]: ["fixed_role", "run", "evidence"],
192
+ [HARNESS_SESSION_ROLE.failureAnalyzer]: ["fixed_role", "run", "task", "evidence"],
193
+ [HARNESS_SESSION_ROLE.repairWorker]: ["fixed_role", "run", "task", "evidence"],
194
+ };
195
+ /**
196
+ * Filter facts by layer, keeping only those whose kind matches the
197
+ * requested layers.
198
+ */
199
+ export const filterFactsByLayer = (facts, layers) => {
200
+ const layerSet = new Set(layers);
201
+ return facts.filter((fact) => {
202
+ switch (fact.kind) {
203
+ case "requirement":
204
+ case "constraint":
205
+ return layerSet.has("run") || layerSet.has("task");
206
+ case "evidence":
207
+ return layerSet.has("evidence");
208
+ case "governance":
209
+ return layerSet.has("governance");
210
+ case "unresolved_issue":
211
+ return layerSet.has("run") || layerSet.has("governance");
212
+ case "workspace":
213
+ return layerSet.has("task");
214
+ default:
215
+ return true;
216
+ }
217
+ });
218
+ };
219
+ //# sourceMappingURL=context-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.js","sourceRoot":"","sources":["../../src/controller/context-budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ControllerIdSource } from "../controller/contracts.js";
2
+ import { type ContextSnapshot } from "../domain/context-snapshot.js";
3
+ import type { Evidence } from "../domain/evidence.js";
4
+ import type { Run, Task } from "../domain/index.js";
5
+ export { computeContextDigest, toContextSummary } from "../domain/context-snapshot.js";
6
+ export type BuildContextSnapshotInput = {
7
+ readonly ids: ControllerIdSource;
8
+ readonly run: Run;
9
+ /** Optional task – when building a task-level snapshot */
10
+ readonly task?: Task;
11
+ /** The execution phase (e.g. "planning", "executing", "verifying") */
12
+ readonly phase: string;
13
+ /** Prior context to derive from, if any */
14
+ readonly parentContextId?: string;
15
+ readonly parentVersion?: number;
16
+ /** Current attempt number (0-based) */
17
+ readonly attempt?: number;
18
+ /** Evidence array from the run, for digest production */
19
+ readonly evidence?: readonly Evidence[];
20
+ /** Unresolved issues / blocking questions */
21
+ readonly unresolvedIssues?: readonly string[];
22
+ };
23
+ /**
24
+ * Build a versioned ContextSnapshot from Run, Task, Evidence, and governance state.
25
+ */
26
+ export declare const buildContextSnapshot: (input: BuildContextSnapshotInput) => ContextSnapshot;
27
+ //# sourceMappingURL=context-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/controller/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAGL,KAAK,eAAe,EAGrB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,KAAK,EAAE,GAAG,EAAiB,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAGlE,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAItF,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAA;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;IACpB,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IACvC,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC9C,CAAA;AAID;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,yBAAyB,KAAG,eA2DvE,CAAA"}
@@ -0,0 +1,184 @@
1
+ import { computeContextDigest, } from "../domain/context-snapshot.js";
2
+ // Re-export the domain helpers for convenience
3
+ export { computeContextDigest, toContextSummary } from "../domain/context-snapshot.js";
4
+ // ─── Context builder ───────────────────────────────────────────────────────
5
+ /**
6
+ * Build a versioned ContextSnapshot from Run, Task, Evidence, and governance state.
7
+ */
8
+ export const buildContextSnapshot = (input) => {
9
+ const { ids, run, task, phase, parentContextId, parentVersion, attempt = 0, evidence = [], unresolvedIssues = [], } = input;
10
+ const contextId = ids.createEventId(`context-${run.runId}-${phase}`);
11
+ const version = parentVersion !== undefined ? parentVersion + 1 : 1;
12
+ const createdAt = new Date().toISOString();
13
+ const facts = buildContextFacts({
14
+ run,
15
+ task,
16
+ governance: run.governance,
17
+ evidence,
18
+ unresolvedIssues,
19
+ });
20
+ const evidenceDigests = buildEvidenceDigests(evidence);
21
+ const worktree = buildWorktree(run);
22
+ const allowedPaths = task?.allowedPaths ?? [];
23
+ const acceptanceCriterionIds = task?.acceptanceCriterionIds ?? run.requirement.acceptanceCriteria.map((c) => c.criterionId);
24
+ const snapshot = {
25
+ schemaVersion: "1.0.0",
26
+ contextId,
27
+ version,
28
+ runId: run.runId,
29
+ taskId: task?.taskId,
30
+ attempt,
31
+ phase,
32
+ goal: run.requirement.summary,
33
+ scope: task?.summary ?? "full",
34
+ facts,
35
+ evidenceDigests,
36
+ worktree,
37
+ allowedPaths,
38
+ acceptanceCriterionIds,
39
+ unresolvedIssues,
40
+ sourceEvents: [],
41
+ parentContextId,
42
+ parentVersion,
43
+ createdAt,
44
+ contentDigest: "",
45
+ };
46
+ const digest = computeContextDigest(snapshot);
47
+ return { ...snapshot, contentDigest: digest };
48
+ };
49
+ // ─── Fact builder ──────────────────────────────────────────────────────────
50
+ const buildContextFacts = (input) => {
51
+ const facts = [];
52
+ // Requirement facts
53
+ facts.push({
54
+ factId: `fact-requirement-${input.run.requirement.requirementId}`,
55
+ kind: "requirement",
56
+ label: "Requirement",
57
+ summary: input.run.requirement.summary,
58
+ priority: 100,
59
+ });
60
+ // Acceptance criteria as individual facts
61
+ for (const criterion of input.run.requirement.acceptanceCriteria) {
62
+ facts.push({
63
+ factId: `fact-acceptance-${criterion.criterionId}`,
64
+ kind: "requirement",
65
+ label: "Acceptance Criterion",
66
+ summary: criterion.text,
67
+ priority: 95,
68
+ });
69
+ }
70
+ // Task-specific facts
71
+ if (input.task !== undefined) {
72
+ facts.push({
73
+ factId: `fact-task-${input.task.taskId}`,
74
+ kind: "constraint",
75
+ label: "Task Summary",
76
+ summary: input.task.summary,
77
+ priority: 90,
78
+ });
79
+ for (const path of input.task.allowedPaths) {
80
+ facts.push({
81
+ factId: `fact-path-${input.task.taskId}-${path.replace(/[^a-z0-9-]/g, "-")}`,
82
+ kind: "constraint",
83
+ label: "Allowed Path",
84
+ summary: path,
85
+ priority: 80,
86
+ });
87
+ }
88
+ const retryBudget = input.task.retryBudget;
89
+ facts.push({
90
+ factId: `fact-retry-${input.task.taskId}`,
91
+ kind: "constraint",
92
+ label: "Retry Budget",
93
+ summary: `Max ${retryBudget.maxAttempts} attempts, ${retryBudget.maxRepairAttempts} repair attempts`,
94
+ priority: 70,
95
+ });
96
+ }
97
+ // Governance facts
98
+ if (input.governance.blockingQuestionId !== null) {
99
+ facts.push({
100
+ factId: `fact-governance-blocking-${input.governance.blockingQuestionId}`,
101
+ kind: "governance",
102
+ label: "Blocking Question",
103
+ summary: `Run is blocked on question ${input.governance.blockingQuestionId}`,
104
+ priority: 100,
105
+ });
106
+ }
107
+ if (input.governance.paused !== null) {
108
+ facts.push({
109
+ factId: `fact-governance-paused`,
110
+ kind: "governance",
111
+ label: "Paused",
112
+ summary: `Run paused: ${input.governance.paused.reason}`,
113
+ priority: 100,
114
+ });
115
+ }
116
+ for (const answer of input.governance.answers) {
117
+ facts.push({
118
+ factId: `fact-governance-answer-${answer.answerId}`,
119
+ kind: "governance",
120
+ label: "Answer",
121
+ summary: answer.answer,
122
+ priority: 85,
123
+ });
124
+ }
125
+ // Evidence facts
126
+ for (const ev of input.evidence) {
127
+ facts.push({
128
+ factId: `fact-evidence-${ev.evidenceId}`,
129
+ kind: "evidence",
130
+ label: `Evidence (${ev.kind})`,
131
+ summary: ev.summary,
132
+ priority: 60,
133
+ sourceRef: ev.evidenceId,
134
+ });
135
+ }
136
+ // Unresolved issues
137
+ for (let index = 0; index < input.unresolvedIssues.length; index++) {
138
+ const issue = input.unresolvedIssues[index];
139
+ facts.push({
140
+ factId: `fact-unresolved-${index}`,
141
+ kind: "unresolved_issue",
142
+ label: "Unresolved Issue",
143
+ summary: issue,
144
+ priority: 100,
145
+ });
146
+ }
147
+ return facts;
148
+ };
149
+ // ─── Evidence digest builder ───────────────────────────────────────────────
150
+ const buildEvidenceDigests = (evidence) => {
151
+ return evidence.map((ev) => ({
152
+ refId: ev.evidenceId,
153
+ summaryDigest: ev.summaryDigest,
154
+ sourceRole: mapEvidenceKindToRole(ev.kind),
155
+ sourceTaskId: ev.taskId,
156
+ createdAt: new Date().toISOString(),
157
+ freshness: "fresh",
158
+ }));
159
+ };
160
+ const mapEvidenceKindToRole = (_kind) => {
161
+ // FIXME: Map evidence kind to agent role more precisely when
162
+ // evidence tracking includes source role metadata.
163
+ return "worker";
164
+ };
165
+ // ─── Worktree builder ──────────────────────────────────────────────────────
166
+ const buildWorktree = (run) => {
167
+ const workspace = run.workspace;
168
+ if (workspace === undefined)
169
+ return undefined;
170
+ const executionRoot = workspace.executionRoot;
171
+ if (executionRoot === undefined)
172
+ return undefined;
173
+ const gitState = workspace.git;
174
+ const branch = gitState.mode === "git" && gitState.headRef !== null ? gitState.headRef : undefined;
175
+ const commit = gitState.mode === "git" && gitState.headRef !== null ? gitState.headRef : undefined;
176
+ const dirty = gitState.mode === "git" ? gitState.dirtyAllowed : false;
177
+ return {
178
+ executionRoot,
179
+ branch,
180
+ commit,
181
+ dirty,
182
+ };
183
+ };
184
+ //# sourceMappingURL=context-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/controller/context-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { ContextEvidenceDigest, ContextSnapshot } from "../domain/context-snapshot.js";
2
+ import type { HarnessSessionRole } from "../session/contracts.js";
3
+ import { type ContextLayer } from "./context-budget.js";
4
+ export type ContextValidationResult = {
5
+ readonly valid: boolean;
6
+ readonly errors: readonly string[];
7
+ readonly warnings: readonly string[];
8
+ };
9
+ export type ConsistencyValidationResult = {
10
+ readonly valid: boolean;
11
+ readonly errors: readonly string[];
12
+ readonly warnings: readonly string[];
13
+ };
14
+ /**
15
+ * Validate that a role is only reading context layers it is authorized for.
16
+ *
17
+ * Returns validation errors for each unauthorized layer access.
18
+ */
19
+ export declare const validateRoleContextLayers: (role: HarnessSessionRole, requestedLayers: readonly ContextLayer[]) => ContextValidationResult;
20
+ /**
21
+ * Validate that a worker's allowedPaths, workingDirectory, and worktree
22
+ * are consistent with the ContextSnapshot it operates from.
23
+ */
24
+ export declare const validateWorkerContextConsistency: (input: {
25
+ readonly snapshot: ContextSnapshot;
26
+ readonly allowedPaths: readonly string[];
27
+ readonly workingDirectory: string;
28
+ readonly worktree?: string | undefined;
29
+ readonly role: HarnessSessionRole;
30
+ }) => ConsistencyValidationResult;
31
+ /**
32
+ * Validate that evidence digests are fresh enough for the current task.
33
+ * Expired or stale evidence generates warnings.
34
+ */
35
+ export declare const validateEvidenceFreshness: (digests: readonly ContextEvidenceDigest[], maxAgeMs?: number) => ContextValidationResult;
36
+ /**
37
+ * Validate that evidence digests from other tasks are not being misused
38
+ * in the current task context.
39
+ */
40
+ export declare const validateCrossTaskEvidence: (digests: readonly ContextEvidenceDigest[], currentTaskId: string) => ContextValidationResult;
41
+ /**
42
+ * Validate that the scope and goal in a context snapshot are consistent
43
+ * with the task being executed.
44
+ */
45
+ export declare const validateScopeConsistency: (snapshot: ContextSnapshot, taskSummary?: string) => ContextValidationResult;
46
+ //# sourceMappingURL=context-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-validation.d.ts","sourceRoot":"","sources":["../../src/controller/context-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,KAAK,YAAY,EAAuB,MAAM,qBAAqB,CAAA;AAI5E,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GACpC,MAAM,kBAAkB,EACxB,iBAAiB,SAAS,YAAY,EAAE,KACvC,uBAkBF,CAAA;AAID;;;GAGG;AACH,eAAO,MAAM,gCAAgC,GAAI,OAAO;IACtD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;CAClC,KAAG,2BA0CH,CAAA;AAID;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,SAAS,qBAAqB,EAAE,EACzC,WAAW,MAAM,KAChB,uBAwBF,CAAA;AAID;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,SAAS,qBAAqB,EAAE,EACzC,eAAe,MAAM,KACpB,uBAaF,CAAA;AAID;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,UAAU,eAAe,EACzB,cAAc,MAAM,KACnB,uBAqBF,CAAA"}