pi-harness-runtime 1.1.394 → 1.1.396

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 (214) hide show
  1. package/AGENTS.md +135 -4
  2. package/harness/glm-quota-logger.ts +17 -0
  3. package/harness/langchain/planner-logger.ts +15 -0
  4. package/harness/service-diagnostics.ts +32 -1
  5. package/index.ts +92 -3
  6. package/package.json +1 -1
  7. package/packages/a2a-adapter/package.json +1 -1
  8. package/packages/agent-policy/package.json +1 -1
  9. package/packages/architecture-generator/package.json +1 -1
  10. package/packages/auth/package.json +1 -1
  11. package/packages/autonomous-refactor/package.json +1 -1
  12. package/packages/autonomous-runtime/package.json +1 -1
  13. package/packages/cache-strategy/package.json +1 -1
  14. package/packages/capability-registry/package.json +1 -1
  15. package/packages/checkpoint/package.json +1 -1
  16. package/packages/cli-plugin-sdk/package.json +1 -1
  17. package/packages/clipboard/package.json +1 -1
  18. package/packages/clipboard-plugin/package.json +1 -1
  19. package/packages/code-generation/package.json +1 -1
  20. package/packages/code-review/package.json +1 -1
  21. package/packages/codex-adapter/package.json +1 -1
  22. package/packages/codex-watcher/package.json +1 -1
  23. package/packages/config-capture/package.json +1 -1
  24. package/packages/connection-runtime/package.json +1 -1
  25. package/packages/context-compiler/package.json +1 -1
  26. package/packages/context-discovery/package.json +1 -1
  27. package/packages/context-manager/package.json +1 -1
  28. package/packages/contracts/dist/workspace-env-format.d.ts +87 -0
  29. package/packages/contracts/dist/workspace-env-format.js +174 -6
  30. package/packages/contracts/dist/workspace-env.js +120 -9
  31. package/packages/contracts/package.json +1 -1
  32. package/packages/contracts/src/workspace-env-format.ts +209 -6
  33. package/packages/contracts/src/workspace-env.ts +128 -7
  34. package/packages/contracts/test/workspace-env.test.ts +177 -0
  35. package/packages/cookie-sanitizer/package.json +1 -1
  36. package/packages/cost-optimizer/package.json +1 -1
  37. package/packages/dependency-analyzer/package.json +1 -1
  38. package/packages/django-plugin/package.json +1 -1
  39. package/packages/doc-generator/package.json +1 -1
  40. package/packages/durable-review/package.json +1 -1
  41. package/packages/e2e-tester/package.json +1 -1
  42. package/packages/evaluation-engine/package.json +1 -1
  43. package/packages/evaluation-runner/package.json +1 -1
  44. package/packages/event-bus/package.json +1 -1
  45. package/packages/event-sink/package.json +1 -1
  46. package/packages/event-store/package.json +1 -1
  47. package/packages/experience-replay/package.json +1 -1
  48. package/packages/feedback-collector/package.json +1 -1
  49. package/packages/file-copy-helper/package.json +1 -1
  50. package/packages/framework-detector/package.json +1 -1
  51. package/packages/framework-plugin-sdk/package.json +1 -1
  52. package/packages/frappe-plugin/package.json +1 -1
  53. package/packages/generic-web-plugin/package.json +1 -1
  54. package/packages/health-monitor/package.json +1 -1
  55. package/packages/intent-analyzer/package.json +1 -1
  56. package/packages/jev-judge/dist/continuation-controller.d.ts +47 -0
  57. package/packages/jev-judge/dist/continuation-controller.d.ts.map +1 -1
  58. package/packages/jev-judge/dist/continuation-controller.js +142 -16
  59. package/packages/jev-judge/dist/continuation-controller.js.map +1 -1
  60. package/packages/jev-judge/dist/index.d.ts +6 -0
  61. package/packages/jev-judge/dist/index.d.ts.map +1 -1
  62. package/packages/jev-judge/dist/index.js +6 -0
  63. package/packages/jev-judge/dist/index.js.map +1 -1
  64. package/packages/jev-judge/dist/validation-ledger.d.ts +129 -0
  65. package/packages/jev-judge/dist/validation-ledger.d.ts.map +1 -0
  66. package/packages/jev-judge/dist/validation-ledger.js +234 -0
  67. package/packages/jev-judge/dist/validation-ledger.js.map +1 -0
  68. package/packages/jev-judge/dist/validation-plan.d.ts +176 -0
  69. package/packages/jev-judge/dist/validation-plan.d.ts.map +1 -0
  70. package/packages/jev-judge/dist/validation-plan.js +293 -0
  71. package/packages/jev-judge/dist/validation-plan.js.map +1 -0
  72. package/packages/jev-judge/dist/validation-tie-breaker.d.ts +48 -0
  73. package/packages/jev-judge/dist/validation-tie-breaker.d.ts.map +1 -0
  74. package/packages/jev-judge/dist/validation-tie-breaker.js +83 -0
  75. package/packages/jev-judge/dist/validation-tie-breaker.js.map +1 -0
  76. package/packages/jev-judge/package.json +1 -1
  77. package/packages/jev-judge/src/continuation-controller.ts +179 -20
  78. package/packages/jev-judge/src/index.ts +41 -0
  79. package/packages/jev-judge/src/validation-ledger.ts +290 -0
  80. package/packages/jev-judge/src/validation-plan.ts +406 -0
  81. package/packages/jev-judge/src/validation-tie-breaker.ts +123 -0
  82. package/packages/jev-judge/tests/continuation-controller.test.ts +167 -0
  83. package/packages/jev-judge/tests/validation-ledger.test.ts +181 -0
  84. package/packages/jev-judge/tests/validation-plan.test.ts +170 -0
  85. package/packages/jev-judge/tests/validation-tie-breaker.test.ts +88 -0
  86. package/packages/knowledge-graph/package.json +1 -1
  87. package/packages/knowledge-retrieval/package.json +1 -1
  88. package/packages/laravel-plugin/package.json +1 -1
  89. package/packages/learning-engine/package.json +1 -1
  90. package/packages/logging/README.md +37 -0
  91. package/packages/logging/dist/buffer.d.ts +33 -0
  92. package/packages/logging/dist/buffer.d.ts.map +1 -0
  93. package/packages/logging/dist/buffer.js +60 -0
  94. package/packages/logging/dist/buffer.js.map +1 -0
  95. package/packages/logging/dist/config.d.ts +40 -0
  96. package/packages/logging/dist/config.d.ts.map +1 -0
  97. package/packages/logging/dist/config.js +114 -0
  98. package/packages/logging/dist/config.js.map +1 -0
  99. package/packages/logging/dist/index.d.ts +32 -0
  100. package/packages/logging/dist/index.d.ts.map +1 -0
  101. package/packages/logging/dist/index.js +31 -0
  102. package/packages/logging/dist/index.js.map +1 -0
  103. package/packages/logging/dist/redact.d.ts +43 -0
  104. package/packages/logging/dist/redact.d.ts.map +1 -0
  105. package/packages/logging/dist/redact.js +220 -0
  106. package/packages/logging/dist/redact.js.map +1 -0
  107. package/packages/logging/dist/sampler.d.ts +37 -0
  108. package/packages/logging/dist/sampler.d.ts.map +1 -0
  109. package/packages/logging/dist/sampler.js +78 -0
  110. package/packages/logging/dist/sampler.js.map +1 -0
  111. package/packages/logging/dist/shipper.d.ts +82 -0
  112. package/packages/logging/dist/shipper.d.ts.map +1 -0
  113. package/packages/logging/dist/shipper.js +238 -0
  114. package/packages/logging/dist/shipper.js.map +1 -0
  115. package/packages/logging/dist/singleton.d.ts +38 -0
  116. package/packages/logging/dist/singleton.d.ts.map +1 -0
  117. package/packages/logging/dist/singleton.js +95 -0
  118. package/packages/logging/dist/singleton.js.map +1 -0
  119. package/packages/logging/dist/spool.d.ts +39 -0
  120. package/packages/logging/dist/spool.d.ts.map +1 -0
  121. package/packages/logging/dist/spool.js +110 -0
  122. package/packages/logging/dist/spool.js.map +1 -0
  123. package/packages/logging/dist/transports/r2.d.ts +31 -0
  124. package/packages/logging/dist/transports/r2.d.ts.map +1 -0
  125. package/packages/logging/dist/transports/r2.js +60 -0
  126. package/packages/logging/dist/transports/r2.js.map +1 -0
  127. package/packages/logging/dist/transports/webhook.d.ts +22 -0
  128. package/packages/logging/dist/transports/webhook.d.ts.map +1 -0
  129. package/packages/logging/dist/transports/webhook.js +37 -0
  130. package/packages/logging/dist/transports/webhook.js.map +1 -0
  131. package/packages/logging/dist/types.d.ts +73 -0
  132. package/packages/logging/dist/types.d.ts.map +1 -0
  133. package/packages/logging/dist/types.js +19 -0
  134. package/packages/logging/dist/types.js.map +1 -0
  135. package/packages/logging/package.json +37 -0
  136. package/packages/logging/src/buffer.ts +77 -0
  137. package/packages/logging/src/config.ts +163 -0
  138. package/packages/logging/src/index.ts +87 -0
  139. package/packages/logging/src/redact.ts +271 -0
  140. package/packages/logging/src/sampler.ts +97 -0
  141. package/packages/logging/src/shipper.ts +281 -0
  142. package/packages/logging/src/singleton.ts +142 -0
  143. package/packages/logging/src/spool.ts +139 -0
  144. package/packages/logging/src/transports/r2.ts +86 -0
  145. package/packages/logging/src/transports/webhook.ts +54 -0
  146. package/packages/logging/src/types.ts +85 -0
  147. package/packages/logging/test/buffer.test.ts +44 -0
  148. package/packages/logging/test/config.test.ts +97 -0
  149. package/packages/logging/test/integration.test.ts +135 -0
  150. package/packages/logging/test/redact.test.ts +109 -0
  151. package/packages/logging/test/sampler.test.ts +57 -0
  152. package/packages/logging/test/shipper.test.ts +152 -0
  153. package/packages/logging/test/spool.test.ts +93 -0
  154. package/packages/mcp-adapter/package.json +1 -1
  155. package/packages/memory-engine/package.json +1 -1
  156. package/packages/milestone-manager/package.json +1 -1
  157. package/packages/model-registry/package.json +1 -1
  158. package/packages/nextjs-plugin/package.json +1 -1
  159. package/packages/notification/package.json +1 -1
  160. package/packages/observability/package.json +1 -1
  161. package/packages/okf-indexer/package.json +1 -1
  162. package/packages/paperclip-integration/package.json +1 -1
  163. package/packages/performance-optimizer/package.json +1 -1
  164. package/packages/permission-mode/package.json +1 -1
  165. package/packages/privilege-broker/package.json +1 -1
  166. package/packages/project-analyzer/package.json +1 -1
  167. package/packages/project-bootstrap/package.json +1 -1
  168. package/packages/projection-engine/package.json +1 -1
  169. package/packages/prompt-compiler/package.json +1 -1
  170. package/packages/prompt-versioning/package.json +1 -1
  171. package/packages/provider-adapter-sdk/package.json +1 -1
  172. package/packages/provider-router/package.json +1 -1
  173. package/packages/provider-selector/package.json +1 -1
  174. package/packages/providers/package.json +1 -1
  175. package/packages/qdrant-skills/package.json +1 -1
  176. package/packages/quota-manager/package.json +1 -1
  177. package/packages/rate-limiter/package.json +1 -1
  178. package/packages/react-vite-plugin/package.json +1 -1
  179. package/packages/relay/package.json +1 -1
  180. package/packages/release-manager/package.json +1 -1
  181. package/packages/requirement-compiler/package.json +1 -1
  182. package/packages/runtime/package.json +1 -1
  183. package/packages/scheduler/package.json +1 -1
  184. package/packages/scheduler-adapter/package.json +1 -1
  185. package/packages/session/package.json +1 -1
  186. package/packages/session-api/package.json +1 -1
  187. package/packages/session-export/package.json +1 -1
  188. package/packages/shared-context/package.json +1 -1
  189. package/packages/skill-mcp-client/package.json +1 -1
  190. package/packages/skill-registry/package.json +1 -1
  191. package/packages/skills/package.json +1 -1
  192. package/packages/sprint-planner/package.json +1 -1
  193. package/packages/subscription-engine/package.json +1 -1
  194. package/packages/task-compiler/package.json +1 -1
  195. package/packages/telegram/package.json +1 -1
  196. package/packages/tencentdb-memory/package.json +1 -1
  197. package/packages/tencentdb-sync/package.json +1 -1
  198. package/packages/test-data-generator/package.json +1 -1
  199. package/packages/test-generator/package.json +1 -1
  200. package/packages/todo-bd-sync/package.json +1 -1
  201. package/packages/token-estimation/package.json +1 -1
  202. package/packages/token-optimizer/package.json +1 -1
  203. package/packages/trajectory/package.json +1 -1
  204. package/packages/tui/package.json +1 -1
  205. package/packages/types/package.json +1 -1
  206. package/packages/voice-api/package.json +1 -1
  207. package/packages/webmcp-tester/package.json +1 -1
  208. package/packages/wiki/package.json +1 -1
  209. package/packages/workflow-events/package.json +1 -1
  210. package/packages/workspace-scanner/package.json +1 -1
  211. package/packages/worktree/package.json +1 -1
  212. package/packages/write-review/package.json +1 -1
  213. package/scripts/unified-webhook-server.ts +102 -0
  214. package/scripts/validation-run.ts +191 -0
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Validation Plan - staged (fast -> full) test tiers for a todo.
3
+ *
4
+ * The harness NEVER guesses a tier from a command string. A tier is declared
5
+ * by the task author in the todo metadata, so the plan stays truthful and
6
+ * reviewable:
7
+ *
8
+ * ```json
9
+ * {
10
+ * "metadata": {
11
+ * "validationPlan": {
12
+ * "fast": { "command": "bun test tests/fast", "expectedDurationMs": 18000, "datasetSize": 100 },
13
+ * "full": { "command": "bun test tests/full", "expectedDurationMs": 2400000, "datasetSize": 10000 },
14
+ * "budgetMinutes": 90,
15
+ * "finalTierRequired": true
16
+ * }
17
+ * }
18
+ * }
19
+ * ```
20
+ *
21
+ * Every field is optional. A todo without a plan keeps the current behaviour
22
+ * (no validation context is injected), so small tasks are unaffected.
23
+ */
24
+ import type { TodoItem } from "./todo-provider.js";
25
+ /**
26
+ * Which side of the ladder a tier sits on.
27
+ *
28
+ * - `fast`: representative, cheap, safe to run after every edit
29
+ * - `full`: complete, expensive, run once as the final acceptance check
30
+ */
31
+ export type ValidationTierKind = "fast" | "full";
32
+ /**
33
+ * One declared validation tier.
34
+ */
35
+ export interface ValidationTier {
36
+ kind: ValidationTierKind;
37
+ /** Exact command for this tier. Never rewritten by the harness. */
38
+ command?: string;
39
+ /** Human label, e.g. "fixture regression". */
40
+ label?: string;
41
+ /** Expected cost of the tier in milliseconds (measured or estimated). */
42
+ expectedDurationMs?: number;
43
+ /** Dataset size the tier exercises, when it is data-volume bound. */
44
+ datasetSize?: number;
45
+ }
46
+ /**
47
+ * State of one tier for one todo item.
48
+ */
49
+ export interface ValidationTierState {
50
+ /** `not-run` when no run was recorded for this tier. */
51
+ status: "passed" | "failed" | "timeout" | "error" | "skipped" | "not-run";
52
+ /** Timestamp of the latest run. */
53
+ at?: string;
54
+ /** Duration of the latest run. */
55
+ durationMs?: number;
56
+ /** Command of the latest run. */
57
+ command?: string;
58
+ }
59
+ /**
60
+ * Aggregated validation state of a todo item.
61
+ */
62
+ export interface ValidationState {
63
+ /** True when the item declares a validation plan. */
64
+ hasPlan: boolean;
65
+ /** State of the cheap tier. */
66
+ fast: ValidationTierState;
67
+ /** State of the expensive tier. */
68
+ full: ValidationTierState;
69
+ /** True when the plan declares the full tier as the final acceptance check. */
70
+ finalTierRequired: boolean;
71
+ /**
72
+ * True when the final tier is required but has not passed yet.
73
+ *
74
+ * A todo in this state must not be reported as complete.
75
+ */
76
+ finalTierPending: boolean;
77
+ /** Soft time budget of the plan, in minutes. */
78
+ budgetMinutes?: number;
79
+ /** True when the plan requires a final tier but does not declare one. */
80
+ planIncomplete: boolean;
81
+ }
82
+ /**
83
+ * The full staged validation plan for a todo.
84
+ */
85
+ export interface ValidationPlan {
86
+ /** Cheap representative tier, used while the code is changing. */
87
+ fast?: ValidationTier;
88
+ /** Expensive complete tier, used once the implementation is stable. */
89
+ full?: ValidationTier;
90
+ /** Extra guidance for the agent (e.g. "fast tier must cover aggregation"). */
91
+ notes?: string;
92
+ /** Soft time budget for this todo, in minutes. */
93
+ budgetMinutes?: number;
94
+ /** When true, the todo must not be completed before the full tier passed. */
95
+ finalTierRequired?: boolean;
96
+ }
97
+ /**
98
+ * Parse a duration into milliseconds.
99
+ *
100
+ * Strings must carry a unit (`45s`, `40m`, `1h`, `1h30m`). A bare number is
101
+ * milliseconds when it is at least 1000 and seconds below that, because a
102
+ * bare "40" is ambiguous between milliseconds and minutes.
103
+ */
104
+ export declare function parseDurationMs(value: unknown): number | undefined;
105
+ /**
106
+ * Format a duration for a human-readable status line.
107
+ */
108
+ export declare function formatDuration(ms: number): string;
109
+ /**
110
+ * Parse one tier declaration.
111
+ *
112
+ * Accepts a plain command string (`"bun test fast"`) or an object with
113
+ * `command`/`label`/`expectedDurationMs`/`datasetSize` fields.
114
+ */
115
+ export declare function parseTier(value: unknown, kind: ValidationTierKind): ValidationTier | undefined;
116
+ /**
117
+ * Read the validation plan of a todo.
118
+ *
119
+ * Returns `null` when the todo declares no plan: ordinary tasks must keep the
120
+ * current behaviour.
121
+ */
122
+ export declare function parseValidationPlan(item: TodoItem | null | undefined): ValidationPlan | null;
123
+ /**
124
+ * Describe one tier in a single line: command, expected cost, dataset size.
125
+ */
126
+ export declare function describeTier(tier: ValidationTier): string;
127
+ /**
128
+ * Status of the soft time budget of a plan.
129
+ */
130
+ export interface ValidationBudgetStatus {
131
+ /** The budget in milliseconds, when the plan declares one. */
132
+ budgetMs?: number;
133
+ /** Time already spent on the item, when it is known. */
134
+ elapsedMs?: number;
135
+ /** Time left before the budget is exhausted. */
136
+ remainingMs?: number;
137
+ /** True when the budget is spent. */
138
+ exhausted: boolean;
139
+ }
140
+ /**
141
+ * Compute the budget status of a plan.
142
+ *
143
+ * There is no implicit budget: only a declared `budgetMinutes` arms it. An
144
+ * invented budget could pause legitimate long work, so the harness never
145
+ * guesses one.
146
+ */
147
+ export declare function validationBudgetStatus(plan: ValidationPlan | null | undefined, elapsedMs?: number): ValidationBudgetStatus;
148
+ /**
149
+ * Aggregate recorded runs into the validation state of an item.
150
+ *
151
+ * The runs are expected in chronological order; the latest run of a tier
152
+ * defines its state.
153
+ */
154
+ export declare function summarizeValidationState(plan: ValidationPlan | null | undefined, runs: {
155
+ ts: string;
156
+ tier: ValidationTierKind;
157
+ status: string;
158
+ }[]): ValidationState;
159
+ /**
160
+ * Render the validation context that is injected into a continuation message.
161
+ *
162
+ * The text is deliberately short: it is added to the steer payload that the
163
+ * agent reads when the harness continues a todo on its own.
164
+ */
165
+ export declare function formatValidationContext(plan: ValidationPlan, opts?: {
166
+ elapsedMs?: number;
167
+ state?: ValidationState;
168
+ }): string;
169
+ /**
170
+ * Convenience wrapper: the validation context of a todo, or an empty string.
171
+ */
172
+ export declare function buildValidationSteerSuffix(item: TodoItem | null | undefined, opts?: {
173
+ elapsedMs?: number;
174
+ state?: ValidationState;
175
+ }): string;
176
+ //# sourceMappingURL=validation-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-plan.d.ts","sourceRoot":"","sources":["../src/validation-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Validation Plan - staged (fast -> full) test tiers for a todo.
3
+ *
4
+ * The harness NEVER guesses a tier from a command string. A tier is declared
5
+ * by the task author in the todo metadata, so the plan stays truthful and
6
+ * reviewable:
7
+ *
8
+ * ```json
9
+ * {
10
+ * "metadata": {
11
+ * "validationPlan": {
12
+ * "fast": { "command": "bun test tests/fast", "expectedDurationMs": 18000, "datasetSize": 100 },
13
+ * "full": { "command": "bun test tests/full", "expectedDurationMs": 2400000, "datasetSize": 10000 },
14
+ * "budgetMinutes": 90,
15
+ * "finalTierRequired": true
16
+ * }
17
+ * }
18
+ * }
19
+ * ```
20
+ *
21
+ * Every field is optional. A todo without a plan keeps the current behaviour
22
+ * (no validation context is injected), so small tasks are unaffected.
23
+ */
24
+ function asRecord(value) {
25
+ if (!value || typeof value !== "object" || Array.isArray(value))
26
+ return null;
27
+ return value;
28
+ }
29
+ function firstString(source, keys) {
30
+ for (const key of keys) {
31
+ const value = source[key];
32
+ if (typeof value === "string" && value.trim().length > 0)
33
+ return value.trim();
34
+ }
35
+ return undefined;
36
+ }
37
+ function firstNumber(source, keys) {
38
+ for (const key of keys) {
39
+ const value = source[key];
40
+ if (typeof value === "number" && Number.isFinite(value))
41
+ return value;
42
+ }
43
+ return undefined;
44
+ }
45
+ /**
46
+ * Parse a duration into milliseconds.
47
+ *
48
+ * Strings must carry a unit (`45s`, `40m`, `1h`, `1h30m`). A bare number is
49
+ * milliseconds when it is at least 1000 and seconds below that, because a
50
+ * bare "40" is ambiguous between milliseconds and minutes.
51
+ */
52
+ export function parseDurationMs(value) {
53
+ if (typeof value === "number") {
54
+ if (!Number.isFinite(value))
55
+ return undefined;
56
+ return value >= 1000 ? value : Math.round(value * 1000);
57
+ }
58
+ if (typeof value !== "string")
59
+ return undefined;
60
+ const text = value.trim().toLowerCase();
61
+ if (!text)
62
+ return undefined;
63
+ const match = /^(?:(\d+(?:\.\d+)?)h)?\s*(?:(\d+(?:\.\d+)?)m)?\s*(?:(\d+(?:\.\d+)?)s)?$/.exec(text);
64
+ if (!match || (!match[1] && !match[2] && !match[3]))
65
+ return undefined;
66
+ const hours = match[1] ? Number(match[1]) : 0;
67
+ const minutes = match[2] ? Number(match[2]) : 0;
68
+ const seconds = match[3] ? Number(match[3]) : 0;
69
+ if (hours === 0 && minutes === 0 && seconds === 0)
70
+ return undefined;
71
+ return Math.round((hours * 3600 + minutes * 60 + seconds) * 1000);
72
+ }
73
+ /**
74
+ * Format a duration for a human-readable status line.
75
+ */
76
+ export function formatDuration(ms) {
77
+ if (!Number.isFinite(ms) || ms < 0)
78
+ return "0s";
79
+ const seconds = Math.round(ms / 1000);
80
+ if (seconds < 60)
81
+ return `${seconds}s`;
82
+ const minutes = Math.round(seconds / 60);
83
+ if (minutes < 60)
84
+ return `${minutes}m`;
85
+ const hours = Math.floor(minutes / 60);
86
+ const rest = minutes % 60;
87
+ return rest === 0 ? `${hours}h` : `${hours}h ${rest}m`;
88
+ }
89
+ /**
90
+ * Parse one tier declaration.
91
+ *
92
+ * Accepts a plain command string (`"bun test fast"`) or an object with
93
+ * `command`/`label`/`expectedDurationMs`/`datasetSize` fields.
94
+ */
95
+ export function parseTier(value, kind) {
96
+ if (typeof value === "string") {
97
+ const command = value.trim();
98
+ if (!command)
99
+ return undefined;
100
+ return { kind, command };
101
+ }
102
+ const record = asRecord(value);
103
+ if (!record)
104
+ return undefined;
105
+ const command = firstString(record, ["command", "cmd", "run"]);
106
+ const label = firstString(record, ["label", "name", "description"]);
107
+ const expectedDurationMs = firstNumber(record, ["expectedDurationMs", "expectedCostMs", "durationMs"])
108
+ ?? parseDurationMs(record.expectedDuration ?? record.expectedCost ?? record.duration);
109
+ const datasetSize = firstNumber(record, ["datasetSize", "records", "rows"]);
110
+ if (!command && !label && expectedDurationMs === undefined && datasetSize === undefined) {
111
+ return undefined;
112
+ }
113
+ return { kind, command, label, expectedDurationMs, datasetSize };
114
+ }
115
+ /**
116
+ * Read the validation plan of a todo.
117
+ *
118
+ * Returns `null` when the todo declares no plan: ordinary tasks must keep the
119
+ * current behaviour.
120
+ */
121
+ export function parseValidationPlan(item) {
122
+ const metadata = asRecord(item?.metadata);
123
+ if (!metadata)
124
+ return null;
125
+ const raw = asRecord(metadata.validationPlan)
126
+ ?? asRecord(metadata.validation)
127
+ ?? asRecord(metadata.validation_plan);
128
+ if (!raw)
129
+ return null;
130
+ const tiers = asRecord(raw.tiers);
131
+ const plan = {};
132
+ const fast = parseTier(raw.fast, "fast")
133
+ ?? parseTier(raw.fastCommand ?? raw.fastTier ?? tiers?.fast, "fast");
134
+ const full = parseTier(raw.full, "full")
135
+ ?? parseTier(raw.fullCommand ?? raw.fullTier ?? tiers?.full, "full");
136
+ if (fast)
137
+ plan.fast = fast;
138
+ if (full)
139
+ plan.full = full;
140
+ const notes = firstString(raw, ["notes", "note"]);
141
+ if (notes)
142
+ plan.notes = notes;
143
+ const budgetMinutes = firstNumber(raw, ["budgetMinutes", "budgetMins", "timeBudgetMinutes"]);
144
+ if (budgetMinutes !== undefined)
145
+ plan.budgetMinutes = budgetMinutes;
146
+ if (typeof raw.finalTierRequired === "boolean")
147
+ plan.finalTierRequired = raw.finalTierRequired;
148
+ if (!plan.fast && !plan.full && plan.notes === undefined && plan.budgetMinutes === undefined) {
149
+ return null;
150
+ }
151
+ return plan;
152
+ }
153
+ /**
154
+ * Describe one tier in a single line: command, expected cost, dataset size.
155
+ */
156
+ export function describeTier(tier) {
157
+ const what = tier.command ? `\`${tier.command}\`` : tier.label ?? "unspecified tier";
158
+ const extras = [];
159
+ if (tier.expectedDurationMs !== undefined)
160
+ extras.push(`~${formatDuration(tier.expectedDurationMs)}`);
161
+ if (tier.datasetSize !== undefined)
162
+ extras.push(`${tier.datasetSize} records`);
163
+ return extras.length > 0 ? `${what} (${extras.join(", ")})` : what;
164
+ }
165
+ /**
166
+ * Compute the budget status of a plan.
167
+ *
168
+ * There is no implicit budget: only a declared `budgetMinutes` arms it. An
169
+ * invented budget could pause legitimate long work, so the harness never
170
+ * guesses one.
171
+ */
172
+ export function validationBudgetStatus(plan, elapsedMs) {
173
+ if (!plan || plan.budgetMinutes === undefined) {
174
+ return { elapsedMs, exhausted: false };
175
+ }
176
+ const budgetMs = Math.max(0, plan.budgetMinutes * 60_000);
177
+ const elapsed = elapsedMs ?? 0;
178
+ const remainingMs = Math.max(0, budgetMs - elapsed);
179
+ return {
180
+ budgetMs,
181
+ elapsedMs: elapsed,
182
+ remainingMs,
183
+ exhausted: elapsed >= budgetMs,
184
+ };
185
+ }
186
+ /**
187
+ * Aggregate recorded runs into the validation state of an item.
188
+ *
189
+ * The runs are expected in chronological order; the latest run of a tier
190
+ * defines its state.
191
+ */
192
+ export function summarizeValidationState(plan, runs) {
193
+ const notRun = { status: "not-run" };
194
+ if (!plan) {
195
+ return {
196
+ hasPlan: false,
197
+ fast: { ...notRun },
198
+ full: { ...notRun },
199
+ finalTierRequired: false,
200
+ finalTierPending: false,
201
+ planIncomplete: false,
202
+ };
203
+ }
204
+ const stateOf = (tier) => {
205
+ const matching = runs.filter((run) => run.tier === tier);
206
+ if (matching.length === 0)
207
+ return { ...notRun };
208
+ // The ledger is append-only, so the array order is the chronological
209
+ // order: with an equal timestamp the LATER run wins.
210
+ const latest = matching.reduce((a, b) => (a.ts > b.ts ? a : b));
211
+ const state = { status: latest.status };
212
+ state.at = latest.ts;
213
+ return state;
214
+ };
215
+ const finalTierRequired = plan.finalTierRequired === true;
216
+ const planIncomplete = finalTierRequired && plan.full === undefined;
217
+ const full = stateOf("full");
218
+ const state = {
219
+ hasPlan: true,
220
+ fast: stateOf("fast"),
221
+ full,
222
+ finalTierRequired,
223
+ finalTierPending: finalTierRequired && plan.full !== undefined && full.status !== "passed",
224
+ planIncomplete,
225
+ };
226
+ if (plan.budgetMinutes !== undefined)
227
+ state.budgetMinutes = plan.budgetMinutes;
228
+ return state;
229
+ }
230
+ /**
231
+ * Render the validation context that is injected into a continuation message.
232
+ *
233
+ * The text is deliberately short: it is added to the steer payload that the
234
+ * agent reads when the harness continues a todo on its own.
235
+ */
236
+ export function formatValidationContext(plan, opts = {}) {
237
+ const lines = [];
238
+ const tiers = [];
239
+ if (plan.fast)
240
+ tiers.push(`fast=${describeTier(plan.fast)}`);
241
+ if (plan.full)
242
+ tiers.push(`full=${describeTier(plan.full)}`);
243
+ if (tiers.length === 0 && plan.notes === undefined && plan.budgetMinutes === undefined) {
244
+ return "";
245
+ }
246
+ lines.push(`VALIDATION PLAN (staged): ${tiers.join(" | ") || "no tiers declared"}`);
247
+ if (plan.fast && plan.full) {
248
+ lines.push("Run the fast tier after every edit; run the full tier once when the implementation is stable. " +
249
+ "Do not repeat the full tier after an edit that cannot affect the behavior it covers.");
250
+ }
251
+ if (plan.finalTierRequired) {
252
+ lines.push("The full tier is the final acceptance check: do not complete this todo while it is pending or failed.");
253
+ }
254
+ if (plan.budgetMinutes !== undefined) {
255
+ const budgetMs = plan.budgetMinutes * 60_000;
256
+ const elapsed = opts.elapsedMs;
257
+ const elapsedPart = elapsed === undefined
258
+ ? ""
259
+ : ` (elapsed ${formatDuration(elapsed)}, remaining ${formatDuration(Math.max(0, budgetMs - elapsed))})`;
260
+ lines.push(`Time budget: ${plan.budgetMinutes}m${elapsedPart}. When the budget is reached: stop, report what passed ` +
261
+ "and what is still pending, and do not mark the todo complete.");
262
+ }
263
+ if (plan.notes)
264
+ lines.push(`Notes: ${plan.notes}`);
265
+ // The recorded runs tell the agent what already happened, so it neither
266
+ // repeats a tier that passed nor forgets a pending final tier.
267
+ const state = opts.state;
268
+ if (state?.hasPlan) {
269
+ if (state.fast.status !== "not-run") {
270
+ lines.push(`Fast tier: ${state.fast.status}${state.fast.at ? ` (last run ${state.fast.at})` : ""}.`);
271
+ }
272
+ if (state.full.status !== "not-run") {
273
+ lines.push(`Full tier: ${state.full.status}${state.full.at ? ` (last run ${state.full.at})` : ""}.`);
274
+ }
275
+ if (state.full.status === "passed") {
276
+ lines.push("The final tier already passed. Do not repeat it unless the next change can affect what it covers.");
277
+ }
278
+ if (state.planIncomplete) {
279
+ lines.push("The plan requires a final tier but declares none: report that instead of completing the todo silently.");
280
+ }
281
+ }
282
+ return lines.join("\n");
283
+ }
284
+ /**
285
+ * Convenience wrapper: the validation context of a todo, or an empty string.
286
+ */
287
+ export function buildValidationSteerSuffix(item, opts = {}) {
288
+ const plan = parseValidationPlan(item);
289
+ if (!plan)
290
+ return "";
291
+ return formatValidationContext(plan, opts);
292
+ }
293
+ //# sourceMappingURL=validation-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-plan.js","sourceRoot":"","sources":["../src/validation-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Validation tie-breaker - a typed verdict about one todo item.
3
+ *
4
+ * The judge (Jev) and the harness both need the same question answered with
5
+ * a value instead of prose: "may this item count as done?".
6
+ *
7
+ * The verdict is derived from the declared plan and the recorded runs:
8
+ *
9
+ * - `no-plan` the item declares no validation plan
10
+ * - `complete` the final tier passed, or none was required
11
+ * - `final-tier-pending` the final tier is required and has not passed yet
12
+ * - `final-tier-failed` the final tier ran and did not pass
13
+ * - `plan-incomplete` the plan requires a final tier but declares none
14
+ *
15
+ * A `final-tier-pending` or `final-tier-failed` verdict means the item must
16
+ * not be reported as complete.
17
+ */
18
+ import type { TodoItem } from "./todo-provider.js";
19
+ import type { ValidationState } from "./validation-plan.js";
20
+ /**
21
+ * Typed verdict about the validation state of one item.
22
+ */
23
+ export type ValidationVerdict = "no-plan" | "complete" | "final-tier-pending" | "final-tier-failed" | "plan-incomplete";
24
+ /**
25
+ * The verdict plus the context a caller needs to report it.
26
+ */
27
+ export interface ValidationTieBreaker {
28
+ verdict: ValidationVerdict;
29
+ /** Human readable reason for the verdict. */
30
+ reason: string;
31
+ /** The item the verdict is about. */
32
+ itemId?: number;
33
+ /** Subject of the item. */
34
+ subject?: string;
35
+ /** Status of the final tier, when one ran. */
36
+ tierStatus?: string;
37
+ /** True when the item must not be reported as complete. */
38
+ blocksCompletion: boolean;
39
+ }
40
+ /**
41
+ * Derive the verdict from the validation state of an item.
42
+ */
43
+ export declare function tieBreakValidation(item: TodoItem | null | undefined, state: ValidationState): ValidationTieBreaker;
44
+ /**
45
+ * Format a verdict for a log line or a status line.
46
+ */
47
+ export declare function formatTieBreaker(result: ValidationTieBreaker): string;
48
+ //# sourceMappingURL=validation-tie-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-tie-breaker.d.ts","sourceRoot":"","sources":["../src/validation-tie-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAC1B,SAAS,GACT,UAAU,GACV,oBAAoB,GACpB,mBAAmB,GACnB,iBAAiB,CAAC;AAErB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,EACjC,KAAK,EAAE,eAAe,GACpB,oBAAoB,CA4DtB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAGrE"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Validation tie-breaker - a typed verdict about one todo item.
3
+ *
4
+ * The judge (Jev) and the harness both need the same question answered with
5
+ * a value instead of prose: "may this item count as done?".
6
+ *
7
+ * The verdict is derived from the declared plan and the recorded runs:
8
+ *
9
+ * - `no-plan` the item declares no validation plan
10
+ * - `complete` the final tier passed, or none was required
11
+ * - `final-tier-pending` the final tier is required and has not passed yet
12
+ * - `final-tier-failed` the final tier ran and did not pass
13
+ * - `plan-incomplete` the plan requires a final tier but declares none
14
+ *
15
+ * A `final-tier-pending` or `final-tier-failed` verdict means the item must
16
+ * not be reported as complete.
17
+ */
18
+ /**
19
+ * Derive the verdict from the validation state of an item.
20
+ */
21
+ export function tieBreakValidation(item, state) {
22
+ const base = {
23
+ itemId: item?.id,
24
+ subject: item?.subject,
25
+ };
26
+ if (!state.hasPlan) {
27
+ return {
28
+ ...base,
29
+ verdict: "no-plan",
30
+ reason: "no validation plan declared",
31
+ blocksCompletion: false,
32
+ };
33
+ }
34
+ if (state.planIncomplete) {
35
+ return {
36
+ ...base,
37
+ verdict: "plan-incomplete",
38
+ reason: "the plan requires a final tier but declares none",
39
+ blocksCompletion: true,
40
+ };
41
+ }
42
+ if (!state.finalTierRequired) {
43
+ return {
44
+ ...base,
45
+ verdict: "complete",
46
+ reason: "no final tier required",
47
+ blocksCompletion: false,
48
+ };
49
+ }
50
+ if (state.full.status === "passed") {
51
+ return {
52
+ ...base,
53
+ verdict: "complete",
54
+ reason: "the final tier passed",
55
+ tierStatus: state.full.status,
56
+ blocksCompletion: false,
57
+ };
58
+ }
59
+ if (state.full.status === "not-run") {
60
+ return {
61
+ ...base,
62
+ verdict: "final-tier-pending",
63
+ reason: "the final tier has not run yet",
64
+ tierStatus: state.full.status,
65
+ blocksCompletion: true,
66
+ };
67
+ }
68
+ return {
69
+ ...base,
70
+ verdict: "final-tier-failed",
71
+ reason: `the final tier did not pass (${state.full.status})`,
72
+ tierStatus: state.full.status,
73
+ blocksCompletion: true,
74
+ };
75
+ }
76
+ /**
77
+ * Format a verdict for a log line or a status line.
78
+ */
79
+ export function formatTieBreaker(result) {
80
+ const subject = result.subject ? `${result.subject}: ` : "";
81
+ return `${subject}${result.verdict} (${result.reason})`;
82
+ }
83
+ //# sourceMappingURL=validation-tie-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-tie-breaker.js","sourceRoot":"","sources":["../src/validation-tie-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgCH;;GAEG;AACH,MAAM,UAAU,kBAAkB,CACjC,IAAiC,EACjC,KAAsB;IAEtB,MAAM,IAAI,GAAG;QACZ,MAAM,EAAE,IAAI,EAAE,EAAE;QAChB,OAAO,EAAE,IAAI,EAAE,OAAO;KACtB,CAAC;IAEF,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO;YACN,GAAG,IAAI;YACP,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,6BAA6B;YACrC,gBAAgB,EAAE,KAAK;SACvB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1B,OAAO;YACN,GAAG,IAAI;YACP,OAAO,EAAE,iBAAiB;YAC1B,MAAM,EAAE,kDAAkD;YAC1D,gBAAgB,EAAE,IAAI;SACtB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC9B,OAAO;YACN,GAAG,IAAI;YACP,OAAO,EAAE,UAAU;YACnB,MAAM,EAAE,wBAAwB;YAChC,gBAAgB,EAAE,KAAK;SACvB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO;YACN,GAAG,IAAI;YACP,OAAO,EAAE,UAAU;YACnB,MAAM,EAAE,uBAAuB;YAC/B,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;YAC7B,gBAAgB,EAAE,KAAK;SACvB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO;YACN,GAAG,IAAI;YACP,OAAO,EAAE,oBAAoB;YAC7B,MAAM,EAAE,gCAAgC;YACxC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;YAC7B,gBAAgB,EAAE,IAAI;SACtB,CAAC;IACH,CAAC;IAED,OAAO;QACN,GAAG,IAAI;QACP,OAAO,EAAE,mBAAmB;QAC5B,MAAM,EAAE,gCAAgC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG;QAC5D,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;QAC7B,gBAAgB,EAAE,IAAI;KACtB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAA4B;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC;AACzD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/jev-judge",
3
- "version": "1.1.394",
3
+ "version": "1.1.396",
4
4
  "description": "Jev Judge - Structured decision model for agent routing, E2E testing, and automated decisions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",