@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.
- package/README.md +1 -1
- package/gui/dist/assets/index-BHldBl6_.js +76 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +15 -0
- package/src/adapters/google-antigravity-replay.ts +269 -5
- package/src/adapters/openai-chat.ts +25 -18
- package/src/adapters/openai-responses.ts +63 -17
- package/src/bridge.ts +11 -5
- package/src/claude/inbound.ts +24 -3
- package/src/cli/account-api.ts +2 -0
- package/src/cli/account-extended.ts +262 -1
- package/src/cli/account.ts +3 -1
- package/src/cli/dispatch.ts +532 -0
- package/src/cli/doctor.ts +26 -21
- package/src/cli/help.ts +9 -278
- package/src/cli/index.ts +45 -506
- package/src/cli/lab.ts +171 -65
- package/src/cli/registry.ts +384 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/status.ts +9 -2
- package/src/cli/v2.ts +37 -2
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-store.ts +12 -1
- package/src/codex/admission.ts +2 -1
- package/src/codex/auth-api.ts +3 -2
- package/src/codex/catalog/metadata.ts +6 -4
- package/src/codex/catalog/parsing.ts +31 -7
- package/src/codex/catalog/provider-fetch.ts +2 -1
- package/src/codex/catalog/sync.ts +65 -11
- package/src/codex/features.ts +437 -31
- package/src/codex/history-job.ts +6 -11
- package/src/codex/history-provider.ts +10 -9
- package/src/codex/inject.ts +14 -1
- package/src/codex/native-profile-startup.ts +49 -3
- package/src/codex/native-residue.ts +14 -2
- package/src/codex/paths.ts +75 -1
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/shim.ts +876 -16
- package/src/codex/sync.ts +27 -2
- package/src/config.ts +148 -10
- package/src/generated/compatibility-version.json +2572 -0
- package/src/images/loop.ts +1 -1
- package/src/lab/artifacts/sanitize.ts +3 -3
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +480 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/types.ts +23 -0
- package/src/lab/events/types.ts +2 -1
- package/src/lab/events/validate.ts +2 -1
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +454 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +2 -0
- package/src/lab/ledger/store.ts +173 -0
- package/src/lab/live/executor.ts +29 -4
- package/src/lab/live/transport.ts +3 -1
- package/src/lab/observe/from-conformance.ts +12 -57
- package/src/lab/observe/from-live.ts +9 -1
- package/src/lab/paths.ts +74 -9
- package/src/lab/projection/schema.ts +14 -1
- package/src/lab/projection/verdicts.ts +89 -53
- package/src/lab/projection/verification.ts +83 -3
- package/src/lab/query/catalog.ts +34 -5
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +11 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/subject/installation-salt.ts +24 -4
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +2 -1
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/windows-elevation.ts +8 -1
- package/src/lib/windows-user-principal.ts +62 -2
- package/src/lib/winsw.ts +8 -2
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/google-antigravity.ts +27 -0
- package/src/oauth/health.ts +12 -48
- package/src/oauth/index.ts +122 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/nous.ts +749 -0
- package/src/oauth/store.ts +56 -3
- package/src/providers/codex-capacity.ts +1 -0
- package/src/providers/registry.ts +161 -16
- package/src/responses/custom-tool-compat.ts +182 -0
- package/src/responses/parser.ts +22 -0
- package/src/responses/reasoning-replay-cache.ts +168 -11
- package/src/responses/schema.ts +1 -1
- package/src/router.ts +5 -20
- package/src/routing/capability.ts +9 -3
- package/src/routing/compatibility/assemble.ts +159 -0
- package/src/routing/compatibility/behavior.ts +224 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/evaluator.ts +27 -32
- package/src/routing/profile.ts +118 -4
- package/src/routing/trace.ts +82 -28
- package/src/server/auth-cors.ts +7 -0
- package/src/server/background-lifecycle.ts +20 -7
- package/src/server/chat-completions.ts +2 -2
- package/src/server/claude-messages.ts +6 -3
- package/src/server/direct-local-http.ts +343 -0
- package/src/server/index.ts +80 -18
- package/src/server/lifecycle.ts +12 -4
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/management/agent-settings-routes.ts +27 -3
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +13 -0
- package/src/server/management/logs-usage-routes.ts +1 -0
- package/src/server/management/oauth-account-routes.ts +57 -1
- package/src/server/management/provider-routes.ts +16 -0
- package/src/server/management/routing-profile-routes.ts +12 -24
- package/src/server/management-api.ts +2 -0
- package/src/server/management-auth.ts +68 -3
- package/src/server/proxy-liveness.ts +3 -2
- package/src/server/request-decompress.ts +9 -3
- package/src/server/request-log.ts +53 -4
- package/src/server/responses/collaboration.ts +93 -17
- package/src/server/responses/compact.ts +3 -0
- package/src/server/responses/core.ts +202 -15
- package/src/server/responses/policy-fallback.ts +1 -0
- package/src/server/responses-custom-tool-repair.ts +280 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/startup-action-control.ts +8 -1
- package/src/service.ts +278 -12
- package/src/types.ts +49 -3
- package/src/usage/expected-prices.ts +30 -0
- package/src/usage/log.ts +30 -4
- package/src/usage/summary.ts +153 -2
- package/src/web-search/loop.ts +1 -1
- package/gui/dist/assets/index-Cw1_mxO8.js +0 -70
- 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
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
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 {
|
|
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
|
}
|
package/src/lab/query/catalog.ts
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
24
|
-
suiteDigestFn: (caseRecord: CaseRecord, authority:
|
|
25
|
-
expandFn: (caseRecord: CaseRecord, authority:
|
|
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
|
+
}
|
package/src/lab/query/index.ts
CHANGED
|
@@ -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
|
+
}
|