@piagent/platform 1.5.5 → 1.6.0

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 (227) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +9 -8
  3. package/README.vi.md +9 -5
  4. package/adapters/web-frontend/profile.json +2 -4
  5. package/architecture/layers.json +18 -3
  6. package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
  7. package/benchmarks/deep-logic-v1/grade.mjs +272 -10
  8. package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
  9. package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
  10. package/benchmarks/deep-logic-v1/project/package.json +1 -1
  11. package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
  12. package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
  13. package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
  14. package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
  15. package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
  16. package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
  17. package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
  18. package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
  19. package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
  20. package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
  21. package/benchmarks/deep-logic-v1/suite.json +51 -3
  22. package/benchmarks/deep-logic-v1/variant.mjs +22 -1
  23. package/benchmarks/production-v1/spend-control.v1.json +68 -0
  24. package/benchmarks/production-v1/suite.json +42 -3
  25. package/catalog/capabilities.json +6 -6
  26. package/docs/command-reference-vietnamese.md +6 -6
  27. package/docs/context-engine.md +7 -1
  28. package/docs/distribution-standard.md +7 -7
  29. package/docs/en/architecture.md +1 -0
  30. package/docs/languages.json +4 -4
  31. package/docs/model-options.md +8 -5
  32. package/docs/operator-manual-vietnamese.md +13 -11
  33. package/docs/project-adapters.md +2 -2
  34. package/docs/publishing-for-teams.md +5 -0
  35. package/docs/quality-benchmark.md +271 -62
  36. package/docs/release-install-policy.md +10 -9
  37. package/docs/runtime-policy-design.md +4 -4
  38. package/docs/runtime-quality-baseline.md +13 -6
  39. package/docs/security-threat-model.md +2 -2
  40. package/docs/task-lifecycle-vietnamese.md +2 -2
  41. package/docs/team-onboarding.md +2 -2
  42. package/docs/usage-observability.md +7 -2
  43. package/docs/vi/architecture.md +1 -0
  44. package/docs-site/architecture.html +1 -1
  45. package/docs-site/benchmark.html +1 -1
  46. package/docs-site/commands.html +1 -1
  47. package/docs-site/context-engine.html +1 -1
  48. package/docs-site/en/architecture.html +1 -1
  49. package/docs-site/en/benchmark.html +1 -1
  50. package/docs-site/en/commands.html +1 -1
  51. package/docs-site/en/context-engine.html +1 -1
  52. package/docs-site/en/index.html +1 -1
  53. package/docs-site/en/mcp-approval.html +1 -1
  54. package/docs-site/en/mcp-auth.html +1 -1
  55. package/docs-site/en/mcp-servers.html +1 -1
  56. package/docs-site/en/mcp.html +1 -1
  57. package/docs-site/en/permissions.html +1 -1
  58. package/docs-site/en/profiles.html +1 -1
  59. package/docs-site/en/quickstart.html +1 -1
  60. package/docs-site/en/runtime.html +1 -1
  61. package/docs-site/en/scope.html +1 -1
  62. package/docs-site/en/security.html +1 -1
  63. package/docs-site/en/team.html +1 -1
  64. package/docs-site/en/whats-new.html +1 -1
  65. package/docs-site/en/workflows.html +1 -1
  66. package/docs-site/index.html +1 -1
  67. package/docs-site/mcp-approval.html +1 -1
  68. package/docs-site/mcp-auth.html +1 -1
  69. package/docs-site/mcp-servers.html +1 -1
  70. package/docs-site/mcp.html +1 -1
  71. package/docs-site/permissions.html +1 -1
  72. package/docs-site/profiles.html +1 -1
  73. package/docs-site/quickstart.html +1 -1
  74. package/docs-site/runtime.html +1 -1
  75. package/docs-site/scope.html +1 -1
  76. package/docs-site/security.html +1 -1
  77. package/docs-site/team.html +1 -1
  78. package/docs-site/whats-new.html +1 -1
  79. package/docs-site/workflows.html +1 -1
  80. package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
  81. package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
  82. package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
  83. package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
  84. package/evals/fs4-readiness-matrix.v1.json +2 -2
  85. package/evals/fs5-causal-arm.v1.json +2 -2
  86. package/evals/fs5-pilot-protocol.v1.json +2 -2
  87. package/evals/fs5-pilot-protocol.v4.json +6 -5
  88. package/evals/fs5-pilot-protocol.v5.json +7 -6
  89. package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
  90. package/package.json +3 -1
  91. package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
  92. package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
  93. package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
  94. package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
  95. package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
  96. package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
  97. package/packages/piagent-core/benchmark/benchmark-core.js +732 -661
  98. package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
  99. package/packages/piagent-core/benchmark/benchmark-forensics.js +439 -4
  100. package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
  101. package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
  102. package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
  103. package/packages/piagent-core/benchmark/benchmark-preflight.js +3 -1
  104. package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
  105. package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
  106. package/packages/piagent-core/benchmark/benchmark-record-validation.js +183 -0
  107. package/packages/piagent-core/benchmark/benchmark-report.js +116 -12
  108. package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
  109. package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
  110. package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +782 -0
  111. package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
  112. package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
  113. package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
  114. package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
  115. package/packages/piagent-core/benchmark/benchmark-suite.js +128 -2
  116. package/packages/piagent-core/benchmark/benchmark-summary-support.js +376 -0
  117. package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
  118. package/packages/piagent-core/benchmark/benchmark-usage.js +311 -0
  119. package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
  120. package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
  121. package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
  122. package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
  123. package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
  124. package/packages/piagent-core/extensions/acceptance-receipt.js +34 -11
  125. package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
  126. package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
  127. package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
  128. package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
  129. package/packages/piagent-core/extensions/context-engine.js +148 -145
  130. package/packages/piagent-core/extensions/context-evidence.js +48 -0
  131. package/packages/piagent-core/extensions/context-import-links.js +296 -0
  132. package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
  133. package/packages/piagent-core/extensions/criterion-context-pack.js +422 -7
  134. package/packages/piagent-core/extensions/criterion-graph.js +78 -8
  135. package/packages/piagent-core/extensions/guard-types.ts +2 -0
  136. package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
  137. package/packages/piagent-core/extensions/piagent-guard.ts +233 -41
  138. package/packages/piagent-core/extensions/task-contract-view.js +17 -3
  139. package/packages/piagent-core/extensions/task-lifecycle.js +7 -2
  140. package/packages/piagent-core/extensions/task-state.js +40 -134
  141. package/packages/piagent-core/extensions/verification-intelligence.js +3 -1
  142. package/packages/piagent-core/extensions/workspace-evidence-roots.js +157 -0
  143. package/packages/piagent-core/package.json +1 -1
  144. package/packages/piagent-core/policies/base-policy.json +2 -0
  145. package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
  146. package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
  147. package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
  148. package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
  149. package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
  150. package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
  151. package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
  152. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
  153. package/packages/piagent-core/runtime/hooks/completion-hook.ts +5 -6
  154. package/packages/piagent-core/runtime/hooks/input-hook.ts +11 -1
  155. package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
  156. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +7 -2
  157. package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
  158. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +84 -102
  159. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
  160. package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
  161. package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
  162. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
  163. package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +53 -0
  164. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +34 -6
  165. package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
  166. package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
  167. package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
  168. package/packages/piagent-core/runtime/orchestration/role-policy.ts +1 -1
  169. package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
  170. package/packages/piagent-core/runtime/product/efficiency-metrics.ts +4 -2
  171. package/packages/piagent-core/runtime/quality/exact-output-contract.ts +2 -1
  172. package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
  173. package/packages/piagent-core/runtime/quality/performance-assurance.ts +6 -2
  174. package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
  175. package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
  176. package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +55 -2
  177. package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
  178. package/packages/piagent-core/runtime/registration/context-commands.ts +66 -5
  179. package/packages/piagent-core/runtime/registration/policy-tools.ts +46 -11
  180. package/packages/piagent-core/runtime/registration/task-completion-tools.ts +49 -16
  181. package/packages/piagent-core/runtime/registration/task-start-guidance.ts +163 -0
  182. package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
  183. package/packages/piagent-core/runtime/registration/task-start-tool.ts +67 -62
  184. package/packages/piagent-core/runtime/session/runtime-state.ts +154 -2
  185. package/packages/piagent-core/runtime/session/system-prompt.ts +4 -4
  186. package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
  187. package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
  188. package/packages/piagent-core/runtime/workflows/task-intake.ts +43 -2
  189. package/packages/piagent-core/security/sensitive-data.js +13 -218
  190. package/packages/piagent-core/security/sensitive-project-file.js +42 -0
  191. package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
  192. package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
  193. package/packages/piagent-core/security/sensitive-text.js +234 -0
  194. package/packages/piagent-core/subagents/piagent-worker.md +1 -1
  195. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-CxeZqTte.js} +1 -1
  196. package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +176 -0
  197. package/packages/piagent-webui/dist/client/index.html +1 -1
  198. package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
  199. package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
  200. package/packages/piagent-webui/gateway/gateway-session-stream.ts +93 -7
  201. package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
  202. package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
  203. package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
  204. package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
  205. package/packages/piagent-webui/gateway/session-operation-watchdog.ts +158 -0
  206. package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
  207. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +139 -124
  208. package/packages/piagent-webui/server/loopback-server.ts +8 -0
  209. package/packages/piagent-webui/server/transcript-projection.ts +22 -4
  210. package/packages/piagent-webui/shared/text-visibility.ts +10 -0
  211. package/schemas/piagent-webui/catalog-v1.json +9 -0
  212. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
  213. package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
  214. package/schemas/task-contract.schema.json +12 -1
  215. package/scripts/benchmark-runner-core.mjs +355 -359
  216. package/scripts/benchmark-runner-finalization.mjs +309 -0
  217. package/scripts/benchmark-runner-host-readiness.mjs +94 -0
  218. package/scripts/benchmark-runner-support.mjs +200 -0
  219. package/scripts/benchmark-session.mjs +95 -41
  220. package/scripts/configure-model-scope.sh +4 -3
  221. package/scripts/helper-evaluation.mjs +1 -1
  222. package/scripts/install-global.sh +2 -2
  223. package/scripts/pi-usage-history.mjs +37 -10
  224. package/scripts/setup.sh +2 -2
  225. package/scripts/verify-local.sh +5 -1
  226. package/templates/global/settings.json +2 -1
  227. package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
@@ -25,7 +25,7 @@ function assetError(stage, asset, cause) {
25
25
  return error;
26
26
  }
27
27
 
28
- export function createBenchmarkExecutionGuard({ candidateGuard, suiteRoot, suiteIdentity, piAgentHome, codexCredential, runtimeDependencies, commands }) {
28
+ export function createBenchmarkExecutionGuard({ candidateGuard, suiteRoot, suiteIdentity, piAgentHome, codexCredential, runtimeDependencies, commands, verifyCommandAssets = true }) {
29
29
  const observeAssets = (stage, runtimeHomes = []) => {
30
30
  try {
31
31
  const suite = benchmarkTreeIdentity(suiteRoot, { rejectSymlinks: true });
@@ -61,10 +61,12 @@ export function createBenchmarkExecutionGuard({ candidateGuard, suiteRoot, suite
61
61
  throw assetError(stage, "codex-credential", error);
62
62
  }
63
63
  }
64
- for (const [label, identity] of Object.entries(commands ?? {})) {
65
- if (!identity) continue;
66
- try { verifyBenchmarkCommandIdentity(identity, label, { fullPackageClosure: stage === "finalization" || stage === "prepublish" }); }
67
- catch (error) { throw assetError(stage, `command:${label}`, error); }
64
+ if (verifyCommandAssets) {
65
+ for (const [label, identity] of Object.entries(commands ?? {})) {
66
+ if (!identity) continue;
67
+ try { verifyBenchmarkCommandIdentity(identity, label, { fullPackageClosure: stage === "finalization" || stage === "prepublish" }); }
68
+ catch (error) { throw assetError(stage, `command:${label}`, error); }
69
+ }
68
70
  }
69
71
  };
70
72
  const receipt = (stage, runtimeHomes = []) => {
@@ -329,6 +329,437 @@ export function benchmarkOperationalEvidence(events) {
329
329
  };
330
330
  }
331
331
 
332
+ const causalContextReadTools = new Set(["read", "grep", "find", "ls"]);
333
+ const causalContextShellTools = new Set(["bash", "shell", "exec"]);
334
+ const causalContextCoverageLanesV1 = Object.freeze([
335
+ "telemetry-window",
336
+ "session-lifecycle",
337
+ "criterion-initial-pack",
338
+ "pack-lifecycle",
339
+ "direct-fallback-rereads",
340
+ "managed-prefix"
341
+ ]);
342
+ const causalContextCoverageLanes = Object.freeze([
343
+ ...causalContextCoverageLanesV1,
344
+ "edit-recovery-context"
345
+ ]);
346
+ const causalContextCriterionReasons = new Set([
347
+ "selected",
348
+ "auto-context-disabled",
349
+ "criterion-graph-unavailable",
350
+ "no-candidates",
351
+ "no-readable-selection"
352
+ ]);
353
+ const causalContextMaximumAggregate = 1_000_000_000;
354
+
355
+ function boundedCausalInteger(value) {
356
+ return Number.isSafeInteger(value) && value >= 0 && value <= causalContextMaximumAggregate;
357
+ }
358
+
359
+ function boundedCausalSum(values) {
360
+ let total = 0;
361
+ for (const value of values) {
362
+ if (!boundedCausalInteger(value) || total + value > causalContextMaximumAggregate) return null;
363
+ total += value;
364
+ }
365
+ return total;
366
+ }
367
+
368
+ function normalizeCausalPath(value) {
369
+ if (typeof value !== "string" || !value || value.length > 4_096) return null;
370
+ const normalized = path.posix.normalize(value.replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+/g, "/"));
371
+ if (!normalized || normalized === "." || path.posix.isAbsolute(normalized)
372
+ || normalized === ".." || normalized.startsWith("../")) return null;
373
+ return normalized;
374
+ }
375
+
376
+ function causalContextPackEvent(event, idField) {
377
+ const id = event?.[idField];
378
+ if (typeof id !== "string" || !id || id.length > 200 || !Array.isArray(event.selectedItems)
379
+ || event.selectedItems.length > 10_000 || !boundedCausalInteger(event.estimatedTokens)
380
+ || typeof event.source !== "string" || !event.source || event.source.length > 100) return null;
381
+ const paths = event.selectedItems.map((item) => normalizeCausalPath(item?.path));
382
+ if (paths.some((item) => item === null)) return null;
383
+ const selectedItemEstimatedTokens = boundedCausalSum(event.selectedItems.map((item) => item?.estimatedTokens));
384
+ if (selectedItemEstimatedTokens === null) return null;
385
+ let binding;
386
+ try {
387
+ binding = JSON.stringify([event.source, event.queryHash ?? null, event.confidence ?? null,
388
+ event.estimatedTokens, event.selectedItems]);
389
+ } catch {
390
+ return null;
391
+ }
392
+ return {
393
+ id,
394
+ estimatedTokens: event.estimatedTokens,
395
+ selectedItems: event.selectedItems.length,
396
+ selectedItemEstimatedTokens,
397
+ criterion: event.source === "criterion-pack",
398
+ paths,
399
+ binding
400
+ };
401
+ }
402
+
403
+ function causalContextTask(event, taskByTurn) {
404
+ if (typeof event?.taskRunId === "string" && event.taskRunId) return event.taskRunId;
405
+ if (typeof event?.turnId !== "string" || !event.turnId) return "";
406
+ return taskByTurn.get(event.turnId) ?? "";
407
+ }
408
+
409
+ function causalEditRecoveryEvent(event) {
410
+ const toolCallId = event?.toolCallId;
411
+ const targetPath = normalizeCausalPath(event.targetPath);
412
+ if (typeof toolCallId !== "string" || !toolCallId || toolCallId.length > 200
413
+ || targetPath === null
414
+ || !/^[a-f0-9]{64}$/.test(String(event.contentHash ?? ""))
415
+ || !boundedCausalInteger(event.originalChars)
416
+ || !boundedCausalInteger(event.injectedChars) || event.injectedChars === 0
417
+ || event.injectedChars <= event.originalChars
418
+ || !boundedCausalInteger(event.injectedEstimatedTokens) || event.injectedEstimatedTokens === 0
419
+ || event.sensitiveContentRedacted !== false) return null;
420
+ return {
421
+ toolCallId,
422
+ targetPath,
423
+ taskRunId: typeof event.taskRunId === "string" ? event.taskRunId : "",
424
+ injectedChars: event.injectedChars,
425
+ injectedEstimatedTokens: event.injectedEstimatedTokens
426
+ };
427
+ }
428
+
429
+ /**
430
+ * Persistable causal context evidence for one benchmark session. The projection
431
+ * deliberately drops every path, prompt, hash, identifier and timestamp. Any
432
+ * incomplete lane nulls the aggregate payload so missing telemetry cannot be
433
+ * interpreted as zero context work.
434
+ */
435
+ export function benchmarkCausalContextReceipt(events, {
436
+ surface,
437
+ sessionId,
438
+ criterionExpected = true,
439
+ telemetryTruncated = false,
440
+ telemetryExists = true,
441
+ telemetryIntegrityFailures = 0,
442
+ recoverableTailBytes = 0
443
+ } = {}) {
444
+ if (surface !== "piagent") return {
445
+ schemaVersion: 1,
446
+ evidenceSource: "not-applicable",
447
+ applicability: "not-applicable",
448
+ available: false,
449
+ coverage: {
450
+ status: "not-applicable",
451
+ telemetryTruncated: false,
452
+ telemetryIntegrityFailures: 0,
453
+ recoverableTailBytes: 0,
454
+ criterionExpected: false,
455
+ sessionEventsObserved: 0,
456
+ observedLanes: 0,
457
+ requiredLanes: 0,
458
+ missingLanes: []
459
+ },
460
+ aggregates: null
461
+ };
462
+
463
+ const visible = Array.isArray(events) && typeof sessionId === "string" && sessionId
464
+ ? events.filter((event) => event && typeof event === "object" && event.sessionId === sessionId)
465
+ : [];
466
+ const envelopeFailures = visible.filter((event) => event.schemaVersion !== 2 || event.telemetrySource !== "piagent").length;
467
+ const suppliedIntegrityFailures = boundedCausalInteger(telemetryIntegrityFailures)
468
+ ? telemetryIntegrityFailures
469
+ : causalContextMaximumAggregate;
470
+ const totalIntegrityFailures = boundedCausalSum([suppliedIntegrityFailures, envelopeFailures])
471
+ ?? causalContextMaximumAggregate;
472
+ const promptIndexByTurn = new Map();
473
+ for (const [index, event] of visible.entries()) {
474
+ if (event.event !== "agent_prompt" || typeof event.turnId !== "string" || !event.turnId) continue;
475
+ if (promptIndexByTurn.has(event.turnId)) promptIndexByTurn.set(event.turnId, null);
476
+ else promptIndexByTurn.set(event.turnId, index);
477
+ }
478
+ const offered = new Map(), delivered = new Map(), injected = new Map();
479
+ const criterion = {
480
+ attempts: 0,
481
+ selectedAttempts: 0,
482
+ candidates: 0,
483
+ selectedItems: 0,
484
+ estimatedTokens: 0,
485
+ zeroSelectionReasonCounts: {
486
+ autoContextDisabled: 0,
487
+ criterionGraphUnavailable: 0,
488
+ noCandidates: 0,
489
+ noReadableSelection: 0
490
+ }
491
+ };
492
+ let criterionEvidenceComplete = true, packLifecycleComplete = true;
493
+ for (const [index, event] of visible.entries()) {
494
+ if (event.event === "criterion_context_pack") {
495
+ const promptIndex = promptIndexByTurn.get(event.turnId);
496
+ const valid = boundedCausalInteger(event.selected) && boundedCausalInteger(event.candidates)
497
+ && boundedCausalInteger(event.estimatedTokens) && causalContextCriterionReasons.has(event.reasonCode)
498
+ && event.candidates >= event.selected
499
+ && Number.isInteger(promptIndex) && promptIndex < index
500
+ && ((event.selected > 0 && event.reasonCode === "selected") || (event.selected === 0 && event.reasonCode !== "selected"));
501
+ if (!valid) {
502
+ criterionEvidenceComplete = false;
503
+ continue;
504
+ }
505
+ criterion.attempts += 1;
506
+ criterion.selectedAttempts += event.selected > 0 ? 1 : 0;
507
+ criterion.candidates += event.candidates;
508
+ criterion.selectedItems += event.selected;
509
+ criterion.estimatedTokens += event.estimatedTokens;
510
+ if (event.selected === 0) {
511
+ const key = {
512
+ "auto-context-disabled": "autoContextDisabled",
513
+ "criterion-graph-unavailable": "criterionGraphUnavailable",
514
+ "no-candidates": "noCandidates",
515
+ "no-readable-selection": "noReadableSelection"
516
+ }[event.reasonCode];
517
+ criterion.zeroSelectionReasonCounts[key] += 1;
518
+ }
519
+ if (![criterion.attempts, criterion.selectedAttempts, criterion.candidates, criterion.selectedItems, criterion.estimatedTokens]
520
+ .every(boundedCausalInteger)) criterionEvidenceComplete = false;
521
+ } else if (event.event === "context_pack_offered") {
522
+ const value = causalContextPackEvent(event, "deliveryId");
523
+ if (!value || offered.has(value.id)) packLifecycleComplete = false;
524
+ else offered.set(value.id, { ...value, index });
525
+ } else if (event.event === "context_delivery_confirmed") {
526
+ const id = event.deliveryId;
527
+ if (typeof id !== "string" || !id || id.length > 200 || !boundedCausalInteger(event.selected) || delivered.has(id)) {
528
+ packLifecycleComplete = false;
529
+ } else delivered.set(id, { id, selectedItems: event.selected, index });
530
+ } else if (event.event === "context_pack_injected") {
531
+ const value = causalContextPackEvent(event, "injectionId");
532
+ if (!value || injected.has(value.id)) packLifecycleComplete = false;
533
+ else injected.set(value.id, { ...value, index });
534
+ }
535
+ }
536
+ for (const [id, delivery] of delivered) {
537
+ const offer = offered.get(id), injection = injected.get(id);
538
+ if (!offer || !injection || offer.index >= delivery.index || delivery.index >= injection.index
539
+ || offer.selectedItems !== delivery.selectedItems || delivery.selectedItems !== injection.selectedItems
540
+ || offer.estimatedTokens !== injection.estimatedTokens
541
+ || offer.selectedItemEstimatedTokens !== injection.selectedItemEstimatedTokens
542
+ || offer.binding !== injection.binding) packLifecycleComplete = false;
543
+ }
544
+ for (const id of offered.keys()) if (!delivered.has(id) || !injected.has(id)) packLifecycleComplete = false;
545
+ for (const id of delivered.keys()) if (!offered.has(id) || !injected.has(id)) packLifecycleComplete = false;
546
+ for (const id of injected.keys()) if (!delivered.has(id)) packLifecycleComplete = false;
547
+ const criterionOffered = [...offered.values()].filter((item) => item.criterion);
548
+ const criterionDelivered = [...delivered.keys()].filter((id) => offered.get(id)?.criterion);
549
+ const criterionInjected = [...injected.values()].filter((item) => item.criterion);
550
+ if (criterionExpected === true && criterion.attempts === 0) criterionEvidenceComplete = false;
551
+ if (criterion.selectedAttempts !== criterionOffered.length
552
+ || criterion.selectedItems !== boundedCausalSum(criterionOffered.map((item) => item.selectedItems))
553
+ || criterion.estimatedTokens !== boundedCausalSum(criterionOffered.map((item) => item.estimatedTokens))
554
+ || criterionOffered.length !== criterionDelivered.length
555
+ || criterionDelivered.length !== criterionInjected.length) criterionEvidenceComplete = false;
556
+
557
+ const taskByTurn = new Map(visible
558
+ .filter((event) => event.event === "turn_task_bound" && typeof event.turnId === "string"
559
+ && event.turnId && typeof event.taskRunId === "string" && event.taskRunId)
560
+ .map((event) => [event.turnId, event.taskRunId]));
561
+ const activePackByTask = new Map();
562
+ const pendingDirectReads = new Map(), seenDirectReadIds = new Set();
563
+ let directFallbackRereadCalls = 0, shellToolCallsObserved = 0;
564
+ let fallbackEvidenceComplete = packLifecycleComplete;
565
+ for (const event of visible) {
566
+ if (event.event === "context_pack_injected") {
567
+ const taskRunId = causalContextTask(event, taskByTurn);
568
+ const paths = injected.get(event.injectionId)?.paths;
569
+ if (!taskRunId || !paths) {
570
+ fallbackEvidenceComplete = false;
571
+ continue;
572
+ }
573
+ const selected = activePackByTask.get(taskRunId) ?? new Set();
574
+ for (const selectedPath of paths) selected.add(selectedPath);
575
+ activePackByTask.set(taskRunId, selected);
576
+ continue;
577
+ }
578
+ if (event.event === "tool_call") {
579
+ const toolName = String(event.toolName ?? "").toLowerCase();
580
+ const taskRunId = causalContextTask(event, taskByTurn);
581
+ const selected = activePackByTask.get(taskRunId);
582
+ if (selected && causalContextShellTools.has(toolName)) shellToolCallsObserved += 1;
583
+ if (!selected || !causalContextReadTools.has(toolName)) continue;
584
+ const target = normalizeCausalPath(event.targetPath);
585
+ if (!target || typeof event.toolCallId !== "string" || !event.toolCallId || event.toolCallId.length > 200) {
586
+ fallbackEvidenceComplete = false;
587
+ continue;
588
+ }
589
+ if (!selected.has(target)) continue;
590
+ if (seenDirectReadIds.has(event.toolCallId)) fallbackEvidenceComplete = false;
591
+ else {
592
+ seenDirectReadIds.add(event.toolCallId);
593
+ pendingDirectReads.set(event.toolCallId, target);
594
+ }
595
+ continue;
596
+ }
597
+ const toolCallId = typeof event.toolCallId === "string" ? event.toolCallId : "";
598
+ if (!toolCallId || !pendingDirectReads.has(toolCallId)) continue;
599
+ if (event.event === "tool_decision" && event.decision === "blocked") {
600
+ pendingDirectReads.delete(toolCallId);
601
+ continue;
602
+ }
603
+ if (event.event === "tool_result") {
604
+ if (event.isError !== true) directFallbackRereadCalls += 1;
605
+ pendingDirectReads.delete(toolCallId);
606
+ }
607
+ }
608
+ if (pendingDirectReads.size > 0) fallbackEvidenceComplete = false;
609
+
610
+ const recoverySessionStarts = visible.filter((event) => event.event === "session_start");
611
+ const firstRecoverySessionStart = visible.findIndex((event) => event.event === "session_start");
612
+ const recoveryCapabilityComplete = recoverySessionStarts.length > 0
613
+ && recoverySessionStarts.every((event) => event.editRecoveryContextTelemetryVersion === 1);
614
+ const editRecoveryReceipts = new Map(), editRecoveryResults = new Map();
615
+ let editRecoveryEvidenceComplete = recoveryCapabilityComplete;
616
+ for (const [index, event] of visible.entries()) {
617
+ if (event.event === "edit_recovery_context") {
618
+ const value = causalEditRecoveryEvent(event);
619
+ if (!value || index <= firstRecoverySessionStart || editRecoveryReceipts.has(value.toolCallId)) editRecoveryEvidenceComplete = false;
620
+ else editRecoveryReceipts.set(value.toolCallId, { ...value, index });
621
+ continue;
622
+ }
623
+ if (event.event !== "tool_result") continue;
624
+ const recoveryFailure = ["edit-anchor-not-unique", "edit-anchor-stale"].includes(event.reasonCode);
625
+ if (!recoveryFailure) {
626
+ if (event.editRecoveryContext !== undefined) editRecoveryEvidenceComplete = false;
627
+ continue;
628
+ }
629
+ const toolCallId = event.toolCallId;
630
+ if (typeof toolCallId !== "string" || !toolCallId || toolCallId.length > 200
631
+ || editRecoveryResults.has(toolCallId)
632
+ || index <= firstRecoverySessionStart
633
+ || String(event.toolName ?? "").toLowerCase() !== "edit"
634
+ || event.isError !== true
635
+ || typeof event.editRecoveryContext !== "boolean"
636
+ || normalizeCausalPath(event.targetPath) === null
637
+ || (event.editRecoveryContext === true
638
+ && (!boundedCausalInteger(event.editRecoveryInjectedChars) || event.editRecoveryInjectedChars === 0
639
+ || !boundedCausalInteger(event.editRecoveryEstimatedTokens) || event.editRecoveryEstimatedTokens === 0))
640
+ || (event.editRecoveryContext === false
641
+ && (event.editRecoveryInjectedChars !== undefined || event.editRecoveryEstimatedTokens !== undefined))) {
642
+ editRecoveryEvidenceComplete = false;
643
+ continue;
644
+ }
645
+ editRecoveryResults.set(toolCallId, {
646
+ index,
647
+ injected: event.editRecoveryContext,
648
+ targetPath: normalizeCausalPath(event.targetPath),
649
+ taskRunId: typeof event.taskRunId === "string" ? event.taskRunId : "",
650
+ injectedChars: event.editRecoveryInjectedChars,
651
+ injectedEstimatedTokens: event.editRecoveryEstimatedTokens
652
+ });
653
+ }
654
+ for (const [toolCallId, receipt] of editRecoveryReceipts) {
655
+ const result = editRecoveryResults.get(toolCallId);
656
+ if (!result || result.injected !== true || receipt.index >= result.index
657
+ || receipt.targetPath !== result.targetPath
658
+ || receipt.taskRunId !== result.taskRunId
659
+ || receipt.injectedChars !== result.injectedChars
660
+ || receipt.injectedEstimatedTokens !== result.injectedEstimatedTokens) editRecoveryEvidenceComplete = false;
661
+ }
662
+ for (const [toolCallId, result] of editRecoveryResults) {
663
+ if (result.injected !== editRecoveryReceipts.has(toolCallId)) editRecoveryEvidenceComplete = false;
664
+ }
665
+ const editRecoveryInjectedChars = boundedCausalSum([...editRecoveryReceipts.values()].map((item) => item.injectedChars));
666
+ const editRecoveryEstimatedTokens = boundedCausalSum([...editRecoveryReceipts.values()].map((item) => item.injectedEstimatedTokens));
667
+ editRecoveryEvidenceComplete &&= editRecoveryInjectedChars !== null && editRecoveryEstimatedTokens !== null;
668
+
669
+ const prompts = visible.map((event, index) => ({ event, index }))
670
+ .filter((item) => item.event.event === "agent_prompt");
671
+ const managedPrefixComplete = prompts.length > 0
672
+ && prompts.every((item) => typeof item.event.managedInstructionsCompacted === "boolean");
673
+ const compactedPrompts = prompts.filter((item) => item.event.managedInstructionsCompacted === true).length;
674
+ const lastPromptIndex = prompts.at(-1)?.index ?? -1;
675
+ const lifecycleComplete = prompts.length > 0
676
+ && visible.some((event, index) => index > lastPromptIndex
677
+ && (event.event === "agent_settled" || event.event === "session_shutdown"));
678
+ const offeredTokens = boundedCausalSum([...offered.values()].map((item) => item.estimatedTokens));
679
+ const deliveredTokens = boundedCausalSum([...delivered.keys()].map((id) => offered.get(id)?.estimatedTokens));
680
+ const injectedTokens = boundedCausalSum([...injected.values()].map((item) => item.estimatedTokens));
681
+ const offeredItemTokens = boundedCausalSum([...offered.values()].map((item) => item.selectedItemEstimatedTokens));
682
+ const deliveredItemTokens = boundedCausalSum([...delivered.keys()].map((id) => offered.get(id)?.selectedItemEstimatedTokens));
683
+ const injectedItemTokens = boundedCausalSum([...injected.values()].map((item) => item.selectedItemEstimatedTokens));
684
+ const offeredItems = boundedCausalSum([...offered.values()].map((item) => item.selectedItems));
685
+ const deliveredItems = boundedCausalSum([...delivered.values()].map((item) => item.selectedItems));
686
+ const injectedItems = boundedCausalSum([...injected.values()].map((item) => item.selectedItems));
687
+ const aggregateBoundsComplete = [offeredTokens, deliveredTokens, injectedTokens, offeredItemTokens, deliveredItemTokens,
688
+ injectedItemTokens, offeredItems, deliveredItems, injectedItems]
689
+ .every((value) => value !== null) && boundedCausalInteger(directFallbackRereadCalls)
690
+ && boundedCausalInteger(shellToolCallsObserved);
691
+ packLifecycleComplete &&= aggregateBoundsComplete;
692
+ fallbackEvidenceComplete &&= aggregateBoundsComplete;
693
+
694
+ const lanes = {
695
+ "telemetry-window": telemetryExists === true && telemetryTruncated !== true
696
+ && totalIntegrityFailures === 0 && recoverableTailBytes === 0,
697
+ "session-lifecycle": lifecycleComplete,
698
+ "criterion-initial-pack": criterionEvidenceComplete,
699
+ "pack-lifecycle": packLifecycleComplete,
700
+ "direct-fallback-rereads": fallbackEvidenceComplete,
701
+ "managed-prefix": managedPrefixComplete,
702
+ "edit-recovery-context": editRecoveryEvidenceComplete
703
+ };
704
+ const missingLanes = causalContextCoverageLanes.filter((lane) => lanes[lane] !== true);
705
+ const observedLanes = causalContextCoverageLanes.length - missingLanes.length;
706
+ const available = missingLanes.length === 0;
707
+ const compactions = visible.filter((event) => event.event === "session_compact").length;
708
+ const managedPrefixState = compactedPrompts === 0
709
+ ? "uncompacted"
710
+ : compactedPrompts === prompts.length ? "compacted" : "mixed";
711
+ return {
712
+ schemaVersion: 2,
713
+ evidenceSource: "context-telemetry-closed-aggregate-v2",
714
+ applicability: "piagent",
715
+ available,
716
+ coverage: {
717
+ status: available ? "complete" : visible.length === 0 || !lifecycleComplete ? "unavailable" : "partial",
718
+ telemetryTruncated: telemetryTruncated === true,
719
+ telemetryIntegrityFailures: totalIntegrityFailures,
720
+ recoverableTailBytes: boundedCausalInteger(recoverableTailBytes) ? recoverableTailBytes : causalContextMaximumAggregate,
721
+ criterionExpected: criterionExpected === true,
722
+ sessionEventsObserved: visible.length,
723
+ observedLanes,
724
+ requiredLanes: causalContextCoverageLanes.length,
725
+ missingLanes
726
+ },
727
+ aggregates: available ? {
728
+ packCounts: { offered: offered.size, delivered: delivered.size, injected: injected.size },
729
+ estimatedTokens: { offered: offeredTokens, delivered: deliveredTokens, injected: injectedTokens },
730
+ selectedItemEstimatedTokens: { offered: offeredItemTokens, delivered: deliveredItemTokens, injected: injectedItemTokens },
731
+ selectedItemCounts: { offered: offeredItems, delivered: deliveredItems, injected: injectedItems },
732
+ criterionInitialPack: {
733
+ ...criterion,
734
+ offered: criterionOffered.length,
735
+ delivered: criterionDelivered.length,
736
+ injected: criterionInjected.length
737
+ },
738
+ directFallbackRereads: {
739
+ successfulCalls: directFallbackRereadCalls,
740
+ shellToolCallsObserved,
741
+ definition: "successful-direct-path-tool-call-v1"
742
+ },
743
+ editRecoveryContext: {
744
+ count: editRecoveryReceipts.size,
745
+ failuresObserved: editRecoveryResults.size,
746
+ suppressedFailures: [...editRecoveryResults.values()].filter((item) => item.injected === false).length,
747
+ injectedChars: editRecoveryInjectedChars,
748
+ injectedEstimatedTokens: editRecoveryEstimatedTokens,
749
+ evidenceCoverage: {
750
+ status: "complete",
751
+ observed: editRecoveryReceipts.size,
752
+ comparable: editRecoveryReceipts.size,
753
+ rate: 1
754
+ },
755
+ definition: "matched-edit-recovery-context-receipt-v1"
756
+ },
757
+ compaction: { eventsObserved: compactions, state: compactions > 0 ? "observed" : "not-observed" },
758
+ managedPrefix: { promptsObserved: prompts.length, compactedPrompts, state: managedPrefixState }
759
+ } : null
760
+ };
761
+ }
762
+
332
763
  export function loadReplayFailurePlan(reportPath) {
333
764
  let report;
334
765
  try {
@@ -440,12 +871,13 @@ export function classifyPreUsageFailure(agent, usage, diagnosticInput, { termina
440
871
  const measuredUsage = Number.isInteger(usage?.sessions) && usage.sessions > 0
441
872
  && ["input", "output", "cacheRead", "cacheWrite", "reasoning", "total", "fresh"]
442
873
  .every((field) => Number.isFinite(usage?.[field]) && Number(usage[field]) >= 0)
443
- && Number.isFinite(usage?.cost) && Number(usage.cost) >= 0;
874
+ && usage.fresh === usage.input + usage.output
875
+ && usage.total === usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
444
876
  const measuredZeroUsage = measuredUsage
445
- && ["input", "output", "cacheRead", "cacheWrite", "reasoning", "total", "fresh", "cost"]
877
+ && ["input", "output", "cacheRead", "cacheWrite", "reasoning", "total", "fresh"]
446
878
  .every((field) => Number(usage[field]) === 0);
447
879
  const providerUnavailable = /\b(?:server(?:s)? (?:are )?(?:currently )?overloaded|temporarily unavailable|service unavailable|try again later)\b/.test(diagnostic);
448
- if (agent.code === 0 && terminalProviderError && measuredUsage && providerUnavailable) {
880
+ if ((terminalProviderError || agent.code !== 0) && measuredUsage && providerUnavailable) {
449
881
  const afterUsage = Number(usage.fresh) > 0;
450
882
  return {
451
883
  failure: afterUsage
@@ -467,7 +899,10 @@ export function classifyPreUsageFailure(agent, usage, diagnosticInput, { termina
467
899
  }
468
900
  if (agent.code === 0) return undefined;
469
901
  if (/\b(?:provider|safety|policy|refus(?:al|ed|e)|disallowed|not allowed|cannot assist|can't assist|cyber safety)\b/.test(diagnostic)) {
470
- return { failure: "provider-policy-refusal-with-usage-unavailable", class: "provider-policy", usageStatus: "unknown-after-provider-start", retryable: false };
902
+ return measuredUsage
903
+ ? { failure: "provider-policy-refusal-after-measured-usage", class: "provider-policy", usageStatus: "measured-but-unaccepted", retryable: false }
904
+ : { failure: "provider-policy-refusal-with-usage-unavailable", class: "provider-policy", usageStatus: "unknown-after-provider-start", retryable: false };
471
905
  }
906
+ if (measuredUsage) return { failure: `agent-exit-${agent.code}-after-measured-usage`, class: "agent-process", usageStatus: "measured-but-unaccepted", retryable: false };
472
907
  return { failure: `agent-exit-${agent.code}-with-usage-unavailable`, class: "unknown-cost", usageStatus: "unknown-after-provider-start", retryable: true };
473
908
  }