@bitkyc08/opencodex 2.12.0 → 2.13.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 (173) hide show
  1. package/README.md +1 -1
  2. package/gui/dist/assets/index-BHldBl6_.js +76 -0
  3. package/gui/dist/index.html +1 -1
  4. package/package.json +1 -1
  5. package/src/adapters/anthropic-output-schema.ts +137 -0
  6. package/src/adapters/anthropic.ts +15 -0
  7. package/src/adapters/google-antigravity-replay.ts +269 -5
  8. package/src/adapters/openai-chat.ts +25 -18
  9. package/src/adapters/openai-responses.ts +63 -17
  10. package/src/bridge.ts +11 -5
  11. package/src/claude/inbound.ts +24 -3
  12. package/src/cli/account-api.ts +2 -0
  13. package/src/cli/account-extended.ts +262 -1
  14. package/src/cli/account.ts +3 -1
  15. package/src/cli/dispatch.ts +532 -0
  16. package/src/cli/doctor.ts +26 -21
  17. package/src/cli/help.ts +9 -278
  18. package/src/cli/index.ts +45 -506
  19. package/src/cli/lab.ts +171 -65
  20. package/src/cli/registry.ts +384 -0
  21. package/src/cli/root.ts +86 -0
  22. package/src/cli/status.ts +9 -2
  23. package/src/cli/v2.ts +37 -2
  24. package/src/codex/account-label.ts +14 -1
  25. package/src/codex/account-store.ts +12 -1
  26. package/src/codex/admission.ts +2 -1
  27. package/src/codex/auth-api.ts +3 -2
  28. package/src/codex/catalog/metadata.ts +6 -4
  29. package/src/codex/catalog/parsing.ts +31 -7
  30. package/src/codex/catalog/provider-fetch.ts +2 -1
  31. package/src/codex/catalog/sync.ts +65 -11
  32. package/src/codex/features.ts +437 -31
  33. package/src/codex/history-job.ts +6 -11
  34. package/src/codex/history-provider.ts +10 -9
  35. package/src/codex/inject.ts +14 -1
  36. package/src/codex/native-profile-startup.ts +49 -3
  37. package/src/codex/native-residue.ts +14 -2
  38. package/src/codex/paths.ts +75 -1
  39. package/src/codex/reset-credit-recovery.ts +1044 -0
  40. package/src/codex/shim.ts +876 -16
  41. package/src/codex/sync.ts +27 -2
  42. package/src/config.ts +148 -10
  43. package/src/generated/compatibility-version.json +2572 -0
  44. package/src/images/loop.ts +1 -1
  45. package/src/lab/artifacts/sanitize.ts +3 -3
  46. package/src/lab/automation/budgets.ts +78 -0
  47. package/src/lab/automation/config-persistence.ts +256 -0
  48. package/src/lab/automation/constants.ts +39 -0
  49. package/src/lab/automation/cooldown.ts +103 -0
  50. package/src/lab/automation/dispatch.ts +211 -0
  51. package/src/lab/automation/index.ts +13 -0
  52. package/src/lab/automation/orchestrator.ts +480 -0
  53. package/src/lab/automation/persistence.ts +512 -0
  54. package/src/lab/automation/planner.ts +371 -0
  55. package/src/lab/automation/policy.ts +136 -0
  56. package/src/lab/automation/queue.ts +191 -0
  57. package/src/lab/automation/recovery.ts +24 -0
  58. package/src/lab/automation/route-context.ts +21 -0
  59. package/src/lab/automation/run-key.ts +44 -0
  60. package/src/lab/automation/runs-query.ts +34 -0
  61. package/src/lab/automation/types.ts +160 -0
  62. package/src/lab/conformance/types.ts +23 -0
  63. package/src/lab/events/types.ts +2 -1
  64. package/src/lab/events/validate.ts +2 -1
  65. package/src/lab/fabric/constants.ts +40 -0
  66. package/src/lab/fabric/executor.ts +492 -0
  67. package/src/lab/fabric/index.ts +80 -0
  68. package/src/lab/fabric/manifest.ts +222 -0
  69. package/src/lab/fabric/observe.ts +454 -0
  70. package/src/lab/fabric/patch.ts +79 -0
  71. package/src/lab/fabric/producer-child.ts +139 -0
  72. package/src/lab/fabric/producer-isolate.ts +276 -0
  73. package/src/lab/fabric/producer-protocol.ts +61 -0
  74. package/src/lab/fabric/scratch.ts +439 -0
  75. package/src/lab/fabric/subject.ts +106 -0
  76. package/src/lab/fabric/types.ts +134 -0
  77. package/src/lab/fabric/verifier.ts +98 -0
  78. package/src/lab/index.ts +2 -0
  79. package/src/lab/ledger/store.ts +173 -0
  80. package/src/lab/live/executor.ts +29 -4
  81. package/src/lab/live/transport.ts +3 -1
  82. package/src/lab/observe/from-conformance.ts +12 -57
  83. package/src/lab/observe/from-live.ts +9 -1
  84. package/src/lab/paths.ts +74 -9
  85. package/src/lab/projection/schema.ts +14 -1
  86. package/src/lab/projection/verdicts.ts +89 -53
  87. package/src/lab/projection/verification.ts +83 -3
  88. package/src/lab/query/catalog.ts +34 -5
  89. package/src/lab/query/freshness.ts +53 -0
  90. package/src/lab/query/index.ts +11 -0
  91. package/src/lab/query/latest-observation.ts +59 -0
  92. package/src/lab/query/passive-production.ts +159 -0
  93. package/src/lab/subject/installation-salt.ts +24 -4
  94. package/src/lab/subject/protocol-subject.ts +80 -0
  95. package/src/lab/subject/route-subject.ts +2 -1
  96. package/src/lib/fabric-task-execution-authority.ts +7 -0
  97. package/src/lib/fabric-task-host.ts +29 -0
  98. package/src/lib/lab-live-route-production.ts +130 -0
  99. package/src/lib/local-management-capability.ts +100 -0
  100. package/src/lib/server-resource-ownership.ts +71 -0
  101. package/src/lib/windows-elevation.ts +8 -1
  102. package/src/lib/windows-user-principal.ts +62 -2
  103. package/src/lib/winsw.ts +8 -2
  104. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  105. package/src/oauth/account-import/index.ts +15 -0
  106. package/src/oauth/account-import/parser.ts +83 -0
  107. package/src/oauth/account-import/registry.ts +18 -0
  108. package/src/oauth/account-import/service.ts +75 -0
  109. package/src/oauth/account-import/types.ts +91 -0
  110. package/src/oauth/anthropic.ts +12 -1
  111. package/src/oauth/callback-server.ts +8 -2
  112. package/src/oauth/chatgpt.ts +12 -1
  113. package/src/oauth/google-antigravity.ts +27 -0
  114. package/src/oauth/health.ts +12 -48
  115. package/src/oauth/index.ts +122 -0
  116. package/src/oauth/kimi.ts +16 -2
  117. package/src/oauth/nous.ts +749 -0
  118. package/src/oauth/store.ts +56 -3
  119. package/src/providers/codex-capacity.ts +1 -0
  120. package/src/providers/registry.ts +161 -16
  121. package/src/responses/custom-tool-compat.ts +182 -0
  122. package/src/responses/parser.ts +22 -0
  123. package/src/responses/reasoning-replay-cache.ts +168 -11
  124. package/src/responses/schema.ts +1 -1
  125. package/src/router.ts +5 -20
  126. package/src/routing/capability.ts +9 -3
  127. package/src/routing/compatibility/assemble.ts +159 -0
  128. package/src/routing/compatibility/behavior.ts +224 -0
  129. package/src/routing/compatibility/catalog.ts +99 -0
  130. package/src/routing/compatibility/endpoint.ts +52 -0
  131. package/src/routing/compatibility/policy.ts +181 -0
  132. package/src/routing/compatibility/reader.ts +110 -0
  133. package/src/routing/compatibility/subject.ts +191 -0
  134. package/src/routing/compatibility/types.ts +64 -0
  135. package/src/routing/compatibility/version.ts +104 -0
  136. package/src/routing/evaluator.ts +27 -32
  137. package/src/routing/profile.ts +118 -4
  138. package/src/routing/trace.ts +82 -28
  139. package/src/server/auth-cors.ts +7 -0
  140. package/src/server/background-lifecycle.ts +20 -7
  141. package/src/server/chat-completions.ts +2 -2
  142. package/src/server/claude-messages.ts +6 -3
  143. package/src/server/direct-local-http.ts +343 -0
  144. package/src/server/index.ts +80 -18
  145. package/src/server/lifecycle.ts +12 -4
  146. package/src/server/local-management-read-client.ts +90 -0
  147. package/src/server/management/agent-settings-routes.ts +27 -3
  148. package/src/server/management/lab-automation-routes.ts +206 -0
  149. package/src/server/management/lab-routes.ts +13 -0
  150. package/src/server/management/logs-usage-routes.ts +1 -0
  151. package/src/server/management/oauth-account-routes.ts +57 -1
  152. package/src/server/management/provider-routes.ts +16 -0
  153. package/src/server/management/routing-profile-routes.ts +12 -24
  154. package/src/server/management-api.ts +2 -0
  155. package/src/server/management-auth.ts +68 -3
  156. package/src/server/proxy-liveness.ts +3 -2
  157. package/src/server/request-decompress.ts +9 -3
  158. package/src/server/request-log.ts +53 -4
  159. package/src/server/responses/collaboration.ts +93 -17
  160. package/src/server/responses/compact.ts +3 -0
  161. package/src/server/responses/core.ts +202 -15
  162. package/src/server/responses/policy-fallback.ts +1 -0
  163. package/src/server/responses-custom-tool-repair.ts +280 -0
  164. package/src/server/responses-terminal-repair.ts +342 -0
  165. package/src/server/startup-action-control.ts +8 -1
  166. package/src/service.ts +278 -12
  167. package/src/types.ts +49 -3
  168. package/src/usage/expected-prices.ts +30 -0
  169. package/src/usage/log.ts +30 -4
  170. package/src/usage/summary.ts +153 -2
  171. package/src/web-search/loop.ts +1 -1
  172. package/gui/dist/assets/index-Cw1_mxO8.js +0 -70
  173. package/src/cli/internal-dispatch.ts +0 -20
@@ -301,6 +301,50 @@ function isMatchedCapabilityAbsenceControl(obs: ObservationEvent): boolean {
301
301
  );
302
302
  }
303
303
 
304
+ function evaluateRequiredPassVerdict(input: {
305
+ suiteManifest: SuiteManifestV1 | null;
306
+ ordered: ObservationEvent[];
307
+ executionMode: ObservationEvent["executionMode"];
308
+ subject?: ObservationEvent["subject"];
309
+ routeSupportedClaims?: readonly string[];
310
+ fabricCapability?: {
311
+ harnessFeatures: readonly string[];
312
+ platforms: readonly string[];
313
+ routePreconditions: readonly string[];
314
+ };
315
+ loadScenarioManifest?: (digest: string) => Record<string, unknown> | null;
316
+ loadScenarioRequirements?: ProjectVerdictsOptions["loadScenarioRequirements"];
317
+ asOf: number;
318
+ }): { verdict: CompatibilityVerdict; notes: string[] } {
319
+ const notes: string[] = [];
320
+ if (!input.suiteManifest) {
321
+ return { verdict: "PROBED", notes: ["suite_manifest_unavailable"] };
322
+ }
323
+ const evaluation = evaluateAllApplicableRequiredPassV1(
324
+ input.suiteManifest,
325
+ input.ordered,
326
+ input.executionMode,
327
+ {
328
+ subject: input.subject,
329
+ routeSupportedClaims: input.routeSupportedClaims,
330
+ fabricCapability: input.fabricCapability,
331
+ loadScenarioManifest: input.loadScenarioManifest,
332
+ loadScenarioRequirements: input.loadScenarioRequirements,
333
+ asOf: input.asOf,
334
+ },
335
+ );
336
+ notes.push(...evaluation.notes);
337
+ if (evaluation.applicableRequiredScenarioIds.length === 0) {
338
+ return { verdict: "UNKNOWN", notes };
339
+ }
340
+ if (evaluation.canVerify) {
341
+ notes.push("all-applicable-required-pass-v1");
342
+ return { verdict: "VERIFIED", notes };
343
+ }
344
+ notes.push("incomplete_required_coverage");
345
+ return { verdict: "PROBED", notes };
346
+ }
347
+
304
348
  function projectObservationGroup(
305
349
  key: ProjectionKey,
306
350
  ordered: ObservationEvent[],
@@ -310,6 +354,11 @@ function projectObservationGroup(
310
354
  loadScenarioManifest?: (digest: string) => Record<string, unknown> | null;
311
355
  loadScenarioRequirements?: ProjectVerdictsOptions["loadScenarioRequirements"];
312
356
  routeSupportedClaims?: readonly string[];
357
+ fabricCapability?: {
358
+ harnessFeatures: readonly string[];
359
+ platforms: readonly string[];
360
+ routePreconditions: readonly string[];
361
+ };
313
362
  } = {},
314
363
  ): DerivedVerdict {
315
364
  const contributing: string[] = [];
@@ -353,60 +402,47 @@ function projectObservationGroup(
353
402
  verdict = "PROBED";
354
403
  notes.push("mixed_execution_modes");
355
404
  } else if (key.evidenceLayer === "protocol_conformance" && newestCurrent?.executionMode === "fixture") {
356
- if (!suiteManifest) {
357
- verdict = "PROBED";
358
- notes.push("suite_manifest_unavailable");
359
- } else {
360
- const evaluation = evaluateAllApplicableRequiredPassV1(
361
- suiteManifest,
362
- ordered,
363
- newestCurrent.executionMode,
364
- {
365
- subject: newestCurrent.subject.subjectKind === "protocol" ? newestCurrent.subject : undefined,
366
- loadScenarioManifest: opts.loadScenarioManifest,
367
- loadScenarioRequirements: opts.loadScenarioRequirements,
368
- asOf,
369
- },
370
- );
371
- notes.push(...evaluation.notes);
372
- if (evaluation.applicableRequiredScenarioIds.length === 0) {
373
- verdict = "UNKNOWN";
374
- } else if (evaluation.canVerify) {
375
- verdict = "VERIFIED";
376
- notes.push("all-applicable-required-pass-v1");
377
- } else {
378
- verdict = "PROBED";
379
- notes.push("incomplete_required_coverage");
380
- }
381
- }
405
+ const evaluated = evaluateRequiredPassVerdict({
406
+ suiteManifest,
407
+ ordered,
408
+ executionMode: newestCurrent.executionMode,
409
+ subject: newestCurrent.subject.subjectKind === "protocol" ? newestCurrent.subject : undefined,
410
+ loadScenarioManifest: opts.loadScenarioManifest,
411
+ loadScenarioRequirements: opts.loadScenarioRequirements,
412
+ asOf,
413
+ });
414
+ verdict = evaluated.verdict;
415
+ notes.push(...evaluated.notes);
382
416
  } else if (key.evidenceLayer === "live_route_compatibility" && newestCurrent?.executionMode === "live") {
383
- if (!suiteManifest) {
384
- verdict = "PROBED";
385
- notes.push("suite_manifest_unavailable");
386
- } else {
387
- const evaluation = evaluateAllApplicableRequiredPassV1(
388
- suiteManifest,
389
- ordered,
390
- newestCurrent.executionMode,
391
- {
392
- subject: newestCurrent.subject.subjectKind === "route" ? newestCurrent.subject : undefined,
393
- routeSupportedClaims: opts.routeSupportedClaims,
394
- loadScenarioManifest: opts.loadScenarioManifest,
395
- loadScenarioRequirements: opts.loadScenarioRequirements,
396
- asOf,
397
- },
398
- );
399
- notes.push(...evaluation.notes);
400
- if (evaluation.applicableRequiredScenarioIds.length === 0) {
401
- verdict = "UNKNOWN";
402
- } else if (evaluation.canVerify) {
403
- verdict = "VERIFIED";
404
- notes.push("all-applicable-required-pass-v1");
405
- } else {
406
- verdict = "PROBED";
407
- notes.push("incomplete_required_coverage");
408
- }
409
- }
417
+ const evaluated = evaluateRequiredPassVerdict({
418
+ suiteManifest,
419
+ ordered,
420
+ executionMode: newestCurrent.executionMode,
421
+ subject: newestCurrent.subject.subjectKind === "route" ? newestCurrent.subject : undefined,
422
+ routeSupportedClaims: opts.routeSupportedClaims,
423
+ loadScenarioManifest: opts.loadScenarioManifest,
424
+ loadScenarioRequirements: opts.loadScenarioRequirements,
425
+ asOf,
426
+ });
427
+ verdict = evaluated.verdict;
428
+ notes.push(...evaluated.notes);
429
+ } else if (key.evidenceLayer === "task_effectiveness" && newestCurrent?.executionMode === "fabric") {
430
+ const evaluated = evaluateRequiredPassVerdict({
431
+ suiteManifest,
432
+ ordered,
433
+ executionMode: newestCurrent.executionMode,
434
+ subject: newestCurrent.subject.subjectKind === "task" ? newestCurrent.subject : undefined,
435
+ fabricCapability: opts.fabricCapability ?? {
436
+ harnessFeatures: ["fabric-scratch-v1"],
437
+ platforms: [process.platform, "*"],
438
+ routePreconditions: ["exact-route-subject"],
439
+ },
440
+ loadScenarioManifest: opts.loadScenarioManifest,
441
+ loadScenarioRequirements: opts.loadScenarioRequirements,
442
+ asOf,
443
+ });
444
+ verdict = evaluated.verdict;
445
+ notes.push(...evaluated.notes);
410
446
  } else {
411
447
  verdict = "PROBED";
412
448
  }
@@ -1,4 +1,4 @@
1
- import type { ObservationEvent, ProtocolSubjectV1, RouteSubjectV1 } from "../events/types";
1
+ import type { ObservationEvent, ProtocolSubjectV1, RouteSubjectV1, TaskSubjectV1 } from "../events/types";
2
2
  import { EVIDENCE_LAYERS, type ExecutionMode } from "../constants";
3
3
  import type { SuiteManifestV1 } from "../conformance/suite-manifest";
4
4
  import type { VerificationRole } from "../conformance/types";
@@ -19,6 +19,9 @@ export interface ScenarioRequirements {
19
19
  upstreamProtocols?: string[];
20
20
  surfaces?: string[];
21
21
  requiredClaims?: string[];
22
+ requiredHarnessFeatures?: string[];
23
+ platforms?: string[];
24
+ routePreconditions?: string[];
22
25
  freshness?: { maxAgeMs: number | null };
23
26
  }
24
27
 
@@ -38,6 +41,7 @@ export function isScenarioApplicable(
38
41
  return true;
39
42
  }
40
43
 
44
+ /** Match protocol subject fields against scenario requirement lists. */
41
45
  function scenarioApplicableToRequirements(
42
46
  requirements: ScenarioRequirements,
43
47
  subject: ProtocolSubjectV1,
@@ -71,10 +75,32 @@ export function routeSubjectApplicableToRequirements(
71
75
  );
72
76
  }
73
77
 
78
+ /** Task-layer applicability against harness/platform/precondition state. */
79
+ export function taskSubjectApplicableToRequirements(
80
+ requirements: ScenarioRequirements,
81
+ capability: {
82
+ harnessFeatures: readonly string[];
83
+ platforms: readonly string[];
84
+ routePreconditions: readonly string[];
85
+ },
86
+ ): boolean {
87
+ const platforms = requirements.platforms ?? ["*"];
88
+ const features = requirements.requiredHarnessFeatures ?? [];
89
+ const preconditions = requirements.routePreconditions ?? [];
90
+ const platformOk = platforms.includes("*")
91
+ || capability.platforms.includes("*")
92
+ || platforms.some((platform) => capability.platforms.includes(platform));
93
+ const featuresOk = features.every((feature) => capability.harnessFeatures.includes(feature));
94
+ const preconditionsOk = preconditions.every((item) => capability.routePreconditions.includes(item));
95
+ return platformOk && featuresOk && preconditionsOk;
96
+ }
97
+
98
+ /** Return true for non-negative integer values used in freshness parsing. */
74
99
  function isNonNegativeInteger(value: unknown): value is number {
75
100
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
76
101
  }
77
102
 
103
+ /** Parse a freshness object from a scenario manifest fragment. */
78
104
  function parseFreshness(value: unknown): { maxAgeMs: number | null } | null {
79
105
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
80
106
  const maxAgeMs = (value as { maxAgeMs?: unknown }).maxAgeMs;
@@ -83,6 +109,7 @@ function parseFreshness(value: unknown): { maxAgeMs: number | null } | null {
83
109
  return { maxAgeMs };
84
110
  }
85
111
 
112
+ /** Parse a string array requirement field from a manifest fragment. */
86
113
  function parseStringArray(value: unknown): string[] | null {
87
114
  if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) return null;
88
115
  return value;
@@ -101,9 +128,28 @@ function scenarioContractFromManifest(
101
128
  if (!inboundProtocols || !upstreamProtocols || !surfaces) return null;
102
129
  const requiredClaims = row.requiredClaims === undefined ? [] : parseStringArray(row.requiredClaims);
103
130
  if (!requiredClaims) return null;
131
+ const requiredHarnessFeatures = row.requiredHarnessFeatures === undefined
132
+ ? []
133
+ : parseStringArray(row.requiredHarnessFeatures);
134
+ if (!requiredHarnessFeatures) return null;
135
+ const platforms = row.platforms === undefined ? ["*"] : parseStringArray(row.platforms);
136
+ if (!platforms) return null;
137
+ const routePreconditions = row.routePreconditions === undefined
138
+ ? []
139
+ : parseStringArray(row.routePreconditions);
140
+ if (!routePreconditions) return null;
104
141
  const freshness = parseFreshness(scenarioManifest.freshness);
105
142
  if (!freshness) return null;
106
- return { inboundProtocols, upstreamProtocols, surfaces, requiredClaims, freshness };
143
+ return {
144
+ inboundProtocols,
145
+ upstreamProtocols,
146
+ surfaces,
147
+ requiredClaims,
148
+ requiredHarnessFeatures,
149
+ platforms,
150
+ routePreconditions,
151
+ freshness,
152
+ };
107
153
  }
108
154
 
109
155
  function effectiveMaxAgeMs(
@@ -139,9 +185,15 @@ export function evaluateAllApplicableRequiredPassV1(
139
185
  observations: ObservationEvent[],
140
186
  executionMode: ExecutionMode,
141
187
  opts: {
142
- subject?: ProtocolSubjectV1 | RouteSubjectV1;
188
+ subject?: ProtocolSubjectV1 | RouteSubjectV1 | TaskSubjectV1;
143
189
  /** For live projection this must come from validated current claim snapshots for subjectId. */
144
190
  routeSupportedClaims?: readonly string[];
191
+ /** Fabric harness/platform/precondition state for task_effectiveness applicability. */
192
+ fabricCapability?: {
193
+ harnessFeatures: readonly string[];
194
+ platforms: readonly string[];
195
+ routePreconditions: readonly string[];
196
+ };
145
197
  loadScenarioManifest?: LoadScenarioManifest;
146
198
  loadScenarioRequirements?: LoadScenarioRequirements;
147
199
  asOf?: number;
@@ -165,6 +217,26 @@ export function evaluateAllApplicableRequiredPassV1(
165
217
  return { applicableRequiredScenarioIds: [], passingRequiredScenarioIds: [], missingRequiredScenarioIds: [], canVerify: false, notes: ["route_claim_state_required"] };
166
218
  }
167
219
  }
220
+ if (suiteManifest.evidenceLayer === "task_effectiveness") {
221
+ if (opts.subject?.subjectKind !== "task") {
222
+ return {
223
+ applicableRequiredScenarioIds: [],
224
+ passingRequiredScenarioIds: [],
225
+ missingRequiredScenarioIds: [],
226
+ canVerify: false,
227
+ notes: ["task_subject_required"],
228
+ };
229
+ }
230
+ if (executionMode !== "fabric") {
231
+ return {
232
+ applicableRequiredScenarioIds: [],
233
+ passingRequiredScenarioIds: [],
234
+ missingRequiredScenarioIds: [],
235
+ canVerify: false,
236
+ notes: ["fabric_execution_mode_required"],
237
+ };
238
+ }
239
+ }
168
240
 
169
241
  const requiredScenarios = suiteManifest.scenarios.filter(
170
242
  (s) => s.role === "required" || s.role === "negative_control",
@@ -198,6 +270,14 @@ export function evaluateAllApplicableRequiredPassV1(
198
270
  if (suiteManifest.evidenceLayer === "live_route_compatibility" && opts.subject?.subjectKind === "route") {
199
271
  if (!routeSubjectApplicableToRequirements(requirements, opts.subject, opts.routeSupportedClaims!)) continue;
200
272
  }
273
+ if (suiteManifest.evidenceLayer === "task_effectiveness" && opts.subject?.subjectKind === "task") {
274
+ const capability = opts.fabricCapability ?? {
275
+ harnessFeatures: ["fabric-scratch-v1"],
276
+ platforms: [process.platform, "*"],
277
+ routePreconditions: ["exact-route-subject"],
278
+ };
279
+ if (!taskSubjectApplicableToRequirements(requirements, capability)) continue;
280
+ }
201
281
  applicableRequired.push(s.id);
202
282
  scenarioMaxAgeById.set(s.id, requirements.freshness?.maxAgeMs ?? null);
203
283
  }
@@ -14,15 +14,31 @@ import {
14
14
  import {
15
15
  suiteManifestDigestForCase,
16
16
  } from "../conformance/suite-manifest";
17
+ import {
18
+ discoverFabricScenarios,
19
+ expandFabricScenario,
20
+ fabricSuiteManifestDigest,
21
+ loadFabricCaseAuthority,
22
+ } from "../fabric/manifest";
17
23
  import { scenarioManifestDigest } from "../digest";
18
- import type { CaseRecord } from "../conformance/types";
24
+ import type { CaseRecord, EvidenceLayer, VerificationRole } from "../conformance/types";
19
25
  import type { CatalogFilters, CatalogScenarioDto } from "./types";
20
26
 
21
- function mapCaseToCatalogScenario(
27
+ type CatalogAuthority = {
28
+ manifestDefaults: {
29
+ version: string;
30
+ suiteVersion: string;
31
+ evidenceLayer: EvidenceLayer;
32
+ verificationRole: VerificationRole;
33
+ freshness: { maxAgeMs: number | null };
34
+ };
35
+ };
36
+
37
+ function mapCaseToCatalogScenario<TAuthority extends CatalogAuthority>(
22
38
  caseRecord: CaseRecord,
23
- authority: ReturnType<typeof loadCaseAuthority>,
24
- suiteDigestFn: (caseRecord: CaseRecord, authority: ReturnType<typeof loadCaseAuthority>) => string,
25
- expandFn: (caseRecord: CaseRecord, authority: ReturnType<typeof loadCaseAuthority>) => Record<string, unknown>,
39
+ authority: TAuthority,
40
+ suiteDigestFn: (caseRecord: CaseRecord, authority: TAuthority) => string,
41
+ expandFn: (caseRecord: CaseRecord, authority: TAuthority) => Record<string, unknown>,
26
42
  ): CatalogScenarioDto {
27
43
  const expanded = expandFn(caseRecord, authority);
28
44
  return {
@@ -62,6 +78,19 @@ export function queryLabCatalog(filters: CatalogFilters = {}): CatalogScenarioDt
62
78
  items.push(mapCaseToCatalogScenario(caseRecord, authority, liveSuiteManifestDigestForCase, expandLiveScenario));
63
79
  }
64
80
  }
81
+ if (!filters.layer || filters.layer === "task_effectiveness") {
82
+ const authority = loadFabricCaseAuthority();
83
+ const suites = filters.suiteId ? [filters.suiteId] : undefined;
84
+ const scenarios = discoverFabricScenarios(authority, suites ?? undefined);
85
+ for (const caseRecord of scenarios) {
86
+ items.push(mapCaseToCatalogScenario(
87
+ caseRecord,
88
+ authority,
89
+ (row, auth) => fabricSuiteManifestDigest(row.suite, auth),
90
+ expandFabricScenario,
91
+ ));
92
+ }
93
+ }
65
94
  return items.sort((a, b) => {
66
95
  const layerCmp = a.evidenceLayer.localeCompare(b.evidenceLayer);
67
96
  if (layerCmp !== 0) return layerCmp;
@@ -0,0 +1,53 @@
1
+ import type { EvidenceLayer } from "../constants";
2
+ import { closeLabReadConnection, openLabReadConnection } from "./connection";
3
+
4
+ export interface ExactObservationIdentity {
5
+ subjectId: string;
6
+ layer: EvidenceLayer;
7
+ suiteId: string;
8
+ suiteVersion: string;
9
+ suiteManifestDigest: string;
10
+ scenarioId: string;
11
+ scenarioVersion: string;
12
+ scenarioManifestDigest: string;
13
+ }
14
+
15
+ /** Return the newest non-excluded observation for one exact evidence identity. */
16
+ export function queryLatestExactObservationCompletedAt(
17
+ identity: ExactObservationIdentity,
18
+ configDir?: string,
19
+ ): number | undefined {
20
+ const conn = openLabReadConnection(configDir);
21
+ try {
22
+ const row = conn.db
23
+ .query(
24
+ `SELECT o.completed_at
25
+ FROM observations o
26
+ JOIN events e ON e.event_id = o.event_id
27
+ WHERE o.subject_id = ?
28
+ AND o.evidence_layer = ?
29
+ AND o.suite_id = ?
30
+ AND o.suite_version = ?
31
+ AND o.suite_manifest_digest = ?
32
+ AND o.scenario_id = ?
33
+ AND o.scenario_version = ?
34
+ AND o.scenario_manifest_digest = ?
35
+ AND e.excluded = 0
36
+ ORDER BY o.completed_at DESC, o.event_id DESC
37
+ LIMIT 1`,
38
+ )
39
+ .get(
40
+ identity.subjectId,
41
+ identity.layer,
42
+ identity.suiteId,
43
+ identity.suiteVersion,
44
+ identity.suiteManifestDigest,
45
+ identity.scenarioId,
46
+ identity.scenarioVersion,
47
+ identity.scenarioManifestDigest,
48
+ ) as { completed_at: number } | null;
49
+ return row ? Number(row.completed_at) : undefined;
50
+ } finally {
51
+ closeLabReadConnection(conn);
52
+ }
53
+ }
@@ -31,4 +31,15 @@ export {
31
31
  queryLabArtifactByDigest,
32
32
  queryLabCatalogEntries,
33
33
  } from "./queries";
34
+ export {
35
+ PASSIVE_PRODUCTION_DEFAULT_LIMIT,
36
+ PASSIVE_PRODUCTION_MAX_LIMIT,
37
+ PASSIVE_PRODUCTION_MAX_SCAN_ROWS,
38
+ derivePassiveProductionSignals,
39
+ queryPassiveProductionSignals,
40
+ type PassiveProductionOutcome,
41
+ type PassiveProductionQueryResultV1,
42
+ type PassiveProductionSummaryV1,
43
+ type PassiveRouteSignalV1,
44
+ } from "./passive-production";
34
45
  export { sanitizePublicText } from "./dto-map";
@@ -0,0 +1,59 @@
1
+ import type { EvidenceLayer } from "../constants";
2
+ import { closeLabReadConnection, openLabReadConnection } from "./connection";
3
+
4
+ export interface LatestLabObservationIdentity {
5
+ layer: EvidenceLayer;
6
+ subjectId: string;
7
+ suiteId: string;
8
+ suiteVersion: string;
9
+ suiteManifestDigest: string;
10
+ scenarioId: string;
11
+ scenarioVersion: string;
12
+ scenarioManifestDigest: string;
13
+ }
14
+
15
+ /**
16
+ * Return the newest non-excluded observation for one exact evidence identity.
17
+ *
18
+ * The projection schema provides a composite index for every identity predicate
19
+ * and the descending freshness order, so planner work is independent of unrelated
20
+ * observation history retained for the same subject.
21
+ */
22
+ export function queryLatestLabObservation(
23
+ identity: LatestLabObservationIdentity,
24
+ configDir?: string,
25
+ ): number | undefined {
26
+ const conn = openLabReadConnection(configDir);
27
+ try {
28
+ const row = conn.db
29
+ .query(
30
+ `SELECT o.completed_at
31
+ FROM observations o
32
+ JOIN events e ON e.event_id = o.event_id
33
+ WHERE o.evidence_layer = ?
34
+ AND o.subject_id = ?
35
+ AND o.suite_id = ?
36
+ AND o.suite_version = ?
37
+ AND o.suite_manifest_digest = ?
38
+ AND o.scenario_id = ?
39
+ AND o.scenario_version = ?
40
+ AND o.scenario_manifest_digest = ?
41
+ AND e.excluded = 0
42
+ ORDER BY o.completed_at DESC, o.event_id DESC
43
+ LIMIT 1`,
44
+ )
45
+ .get(
46
+ identity.layer,
47
+ identity.subjectId,
48
+ identity.suiteId,
49
+ identity.suiteVersion,
50
+ identity.suiteManifestDigest,
51
+ identity.scenarioId,
52
+ identity.scenarioVersion,
53
+ identity.scenarioManifestDigest,
54
+ ) as { completed_at: number } | null;
55
+ return row ? Number(row.completed_at) : undefined;
56
+ } finally {
57
+ closeLabReadConnection(conn);
58
+ }
59
+ }
@@ -0,0 +1,159 @@
1
+ import {
2
+ isLabRouteSubjectId,
3
+ readRecentUsageEntries,
4
+ type PersistedUsageAttempt,
5
+ type PersistedUsageEntry,
6
+ } from "../../usage/log";
7
+
8
+ export const PASSIVE_PRODUCTION_DEFAULT_LIMIT = 50;
9
+ export const PASSIVE_PRODUCTION_MAX_LIMIT = 200;
10
+ export const PASSIVE_PRODUCTION_MAX_SCAN_ROWS = 2_000;
11
+
12
+ export type PassiveProductionOutcome =
13
+ | "success"
14
+ | "client_cancel"
15
+ | "route_error"
16
+ | "environmental"
17
+ | "unknown";
18
+
19
+ export interface PassiveRouteSignalV1 {
20
+ schemaVersion: 1;
21
+ subjectId: string;
22
+ source: "production_usage_v1";
23
+ requestRef: string;
24
+ decisionRef?: string;
25
+ attemptOrdinal: number;
26
+ observedAt: number;
27
+ outcome: PassiveProductionOutcome;
28
+ httpStatus?: number;
29
+ }
30
+
31
+ export interface PassiveProductionSummaryV1 {
32
+ schemaVersion: 1;
33
+ subjectId: string;
34
+ verificationStatus: "not_verification";
35
+ recentProductionAttempts: number;
36
+ recentSuccessfulAttempts: number;
37
+ recentRouteErrorSignals: number;
38
+ lastObservedProductionAttempt?: number;
39
+ }
40
+
41
+ export interface PassiveProductionQueryResultV1 {
42
+ schemaVersion: 1;
43
+ verificationStatus: "not_verification";
44
+ summary: PassiveProductionSummaryV1;
45
+ signals: PassiveRouteSignalV1[];
46
+ scannedRows: number;
47
+ truncated: boolean;
48
+ }
49
+
50
+ const ROUTE_ERROR_CODES = new Set([
51
+ "upstream_error",
52
+ "upstream_transport_error",
53
+ "upstream_connect_error",
54
+ "upstream_timeout",
55
+ ]);
56
+ const ENVIRONMENTAL_ERROR_CODES = new Set([
57
+ "authentication_error",
58
+ "rate_limit_error",
59
+ "admission_rejected",
60
+ "upstream_host_circuit_open",
61
+ ]);
62
+
63
+ function boundedLimit(value: number | undefined): number {
64
+ if (value === undefined) return PASSIVE_PRODUCTION_DEFAULT_LIMIT;
65
+ if (!Number.isSafeInteger(value) || value < 1) throw new RangeError("passive production limit must be a positive integer");
66
+ return Math.min(value, PASSIVE_PRODUCTION_MAX_LIMIT);
67
+ }
68
+
69
+ function isFinalAttempt(entry: PersistedUsageEntry, attempt: PersistedUsageAttempt): boolean {
70
+ const attempts = entry.attempts ?? [];
71
+ return attempts.length > 0 && attempts[attempts.length - 1]?.ordinal === attempt.ordinal;
72
+ }
73
+
74
+ function classifyOutcome(entry: PersistedUsageEntry, attempt: PersistedUsageAttempt): PassiveProductionOutcome {
75
+ if (attempt.status >= 200 && attempt.status < 300) return "success";
76
+ if (isFinalAttempt(entry, attempt) && entry.closeReason === "client_cancel") return "client_cancel";
77
+ if (attempt.errorCode && ENVIRONMENTAL_ERROR_CODES.has(attempt.errorCode)) return "environmental";
78
+ if (attempt.errorCode && ROUTE_ERROR_CODES.has(attempt.errorCode)) return "route_error";
79
+ return "unknown";
80
+ }
81
+
82
+ function signalFor(entry: PersistedUsageEntry, attempt: PersistedUsageAttempt): PassiveRouteSignalV1 | null {
83
+ const subjectId = attempt.labRouteSubjectId;
84
+ if (!isLabRouteSubjectId(subjectId)) return null;
85
+ return {
86
+ schemaVersion: 1,
87
+ subjectId,
88
+ source: "production_usage_v1",
89
+ requestRef: entry.requestId,
90
+ ...(entry.routeDecision?.decisionId ? { decisionRef: entry.routeDecision.decisionId } : {}),
91
+ attemptOrdinal: attempt.ordinal,
92
+ observedAt: entry.timestamp,
93
+ outcome: classifyOutcome(entry, attempt),
94
+ httpStatus: attempt.status,
95
+ };
96
+ }
97
+
98
+ export function derivePassiveProductionSignals(
99
+ entries: readonly PersistedUsageEntry[],
100
+ subjectId: string,
101
+ limit?: number,
102
+ ): PassiveProductionQueryResultV1 {
103
+ if (!isLabRouteSubjectId(subjectId)) throw new Error("invalid passive production subject id");
104
+ const maxResults = boundedLimit(limit);
105
+ const signals: PassiveRouteSignalV1[] = [];
106
+ // readRecentUsageEntries returns the selected append-only rows oldest-first.
107
+ // Tail selection, reverse iteration, and signals[0] as the newest observation rely on this ordering.
108
+ const scanRows = entries.slice(-PASSIVE_PRODUCTION_MAX_SCAN_ROWS);
109
+ const scanTruncated = entries.length > PASSIVE_PRODUCTION_MAX_SCAN_ROWS;
110
+ let resultTruncated = false;
111
+
112
+ scan: for (let rowIndex = scanRows.length - 1; rowIndex >= 0; rowIndex--) {
113
+ const entry = scanRows[rowIndex]!;
114
+ const attempts = entry.attempts ?? [];
115
+ for (let attemptIndex = attempts.length - 1; attemptIndex >= 0; attemptIndex--) {
116
+ const signal = signalFor(entry, attempts[attemptIndex]!);
117
+ if (signal?.subjectId !== subjectId) continue;
118
+ if (signals.length >= maxResults) {
119
+ resultTruncated = true;
120
+ break scan;
121
+ }
122
+ signals.push(signal);
123
+ }
124
+ }
125
+
126
+ const recentSuccessfulAttempts = signals.filter(signal => signal.outcome === "success").length;
127
+ const recentRouteErrorSignals = signals.filter(signal => signal.outcome === "route_error").length;
128
+ return {
129
+ schemaVersion: 1,
130
+ verificationStatus: "not_verification",
131
+ summary: {
132
+ schemaVersion: 1,
133
+ subjectId,
134
+ verificationStatus: "not_verification",
135
+ recentProductionAttempts: signals.length,
136
+ recentSuccessfulAttempts,
137
+ recentRouteErrorSignals,
138
+ ...(signals[0] ? { lastObservedProductionAttempt: signals[0].observedAt } : {}),
139
+ },
140
+ signals,
141
+ scannedRows: scanRows.length,
142
+ truncated: scanTruncated || resultTruncated,
143
+ };
144
+ }
145
+
146
+ /** Read-only bounded CL-09 projection over the existing usage-log authority. */
147
+ export function queryPassiveProductionSignals(
148
+ subjectId: string,
149
+ limit?: number,
150
+ configDir?: string,
151
+ ): PassiveProductionQueryResultV1 {
152
+ return derivePassiveProductionSignals(
153
+ // Read one row past the scan cap so the projection can distinguish an exact-cap history
154
+ // from a history with older rows omitted by the bounded reader.
155
+ readRecentUsageEntries(PASSIVE_PRODUCTION_MAX_SCAN_ROWS + 1, configDir),
156
+ subjectId,
157
+ limit,
158
+ );
159
+ }