omk-protocol 0.96.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 +19 -0
- package/dist/decision.d.ts +4 -0
- package/dist/decision.d.ts.map +1 -0
- package/dist/decision.js +22 -0
- package/dist/decision.js.map +1 -0
- package/dist/evaluation.d.ts +7 -0
- package/dist/evaluation.d.ts.map +1 -0
- package/dist/evaluation.js +144 -0
- package/dist/evaluation.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +11 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +226 -0
- package/dist/validation.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `omk-protocol`
|
|
2
|
+
|
|
3
|
+
Canonical contracts and pure reducers for the OMK Run Protocol.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
TaskSpec -> ExecutionAttempt -> Observation -> EvaluationResult -> RuntimeDecision
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## API
|
|
10
|
+
|
|
11
|
+
- `PROTOCOL_VERSION` (`omk.run.v1`)
|
|
12
|
+
- `TaskSpec`, `ExecutionAttempt`, `Observation`, `ClaimPredicate`
|
|
13
|
+
- `ClaimEvaluation`, `EvaluationResult`, `RuntimeDecision`, `WaiverRecord`
|
|
14
|
+
- Runtime parsers for every top-level record
|
|
15
|
+
- `evaluateTask()` and `reduceRuntimeDecision()`
|
|
16
|
+
|
|
17
|
+
The package does not execute tools, persist records, schedule work, choose providers, or infer topology. Retry and failover counts are derived from attempt records rather than stored counters.
|
|
18
|
+
|
|
19
|
+
See [OMK Run Protocol v1](https://github.com/dmae97/omk/blob/main/packages/coding-agent/docs/run-protocol.md) for evaluation rules, receipt bridging, migration status, and authority boundaries.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type RuntimeDecision, type RuntimeDecisionInput } from "./types.ts";
|
|
2
|
+
/** Pure EvaluationResult -> RuntimeDecision reduction. */
|
|
3
|
+
export declare function reduceRuntimeDecision(input: RuntimeDecisionInput): RuntimeDecision;
|
|
4
|
+
//# sourceMappingURL=decision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAQnH,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,GAAG,eAAe,CAclF","sourcesContent":["import { PROTOCOL_VERSION, type RuntimeAction, type RuntimeDecision, type RuntimeDecisionInput } from \"./types.ts\";\nimport { parseEvaluationResult, parseRuntimeDecision } from \"./validation.ts\";\n\nfunction policyAction(input: RuntimeDecisionInput): RuntimeAction {\n\tif (input.evaluation.semanticVerdict === \"pass\") return \"stop\";\n\treturn input.evaluation.semanticVerdict === \"fail\" ? input.policy.onFail : input.policy.onInconclusive;\n}\n\n/** Pure EvaluationResult -> RuntimeDecision reduction. */\nexport function reduceRuntimeDecision(input: RuntimeDecisionInput): RuntimeDecision {\n\tparseEvaluationResult(input.evaluation);\n\treturn parseRuntimeDecision(\n\t\tObject.freeze({\n\t\t\tschemaVersion: PROTOCOL_VERSION,\n\t\t\tdecisionId: input.decisionId,\n\t\t\ttaskId: input.evaluation.taskId,\n\t\t\tattemptId: input.evaluation.attemptId,\n\t\t\tevaluationId: input.evaluation.evaluationId,\n\t\t\tdecidedAt: input.decidedAt,\n\t\t\taction: policyAction(input),\n\t\t\treasonCode: `evaluation.${input.evaluation.semanticVerdict}`,\n\t\t}),\n\t);\n}\n"]}
|
package/dist/decision.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PROTOCOL_VERSION } from "./types.js";
|
|
2
|
+
import { parseEvaluationResult, parseRuntimeDecision } from "./validation.js";
|
|
3
|
+
function policyAction(input) {
|
|
4
|
+
if (input.evaluation.semanticVerdict === "pass")
|
|
5
|
+
return "stop";
|
|
6
|
+
return input.evaluation.semanticVerdict === "fail" ? input.policy.onFail : input.policy.onInconclusive;
|
|
7
|
+
}
|
|
8
|
+
/** Pure EvaluationResult -> RuntimeDecision reduction. */
|
|
9
|
+
export function reduceRuntimeDecision(input) {
|
|
10
|
+
parseEvaluationResult(input.evaluation);
|
|
11
|
+
return parseRuntimeDecision(Object.freeze({
|
|
12
|
+
schemaVersion: PROTOCOL_VERSION,
|
|
13
|
+
decisionId: input.decisionId,
|
|
14
|
+
taskId: input.evaluation.taskId,
|
|
15
|
+
attemptId: input.evaluation.attemptId,
|
|
16
|
+
evaluationId: input.evaluation.evaluationId,
|
|
17
|
+
decidedAt: input.decidedAt,
|
|
18
|
+
action: policyAction(input),
|
|
19
|
+
reasonCode: `evaluation.${input.evaluation.semanticVerdict}`,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAuE,MAAM,YAAY,CAAC;AACnH,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE9E,SAAS,YAAY,CAAC,KAA2B,EAAiB;IACjE,IAAI,KAAK,CAAC,UAAU,CAAC,eAAe,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IAC/D,OAAO,KAAK,CAAC,UAAU,CAAC,eAAe,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC;AAAA,CACvG;AAED,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB,CAAC,KAA2B,EAAmB;IACnF,qBAAqB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,OAAO,oBAAoB,CAC1B,MAAM,CAAC,MAAM,CAAC;QACb,aAAa,EAAE,gBAAgB;QAC/B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM;QAC/B,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;QACrC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,YAAY;QAC3C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC;QAC3B,UAAU,EAAE,cAAc,KAAK,CAAC,UAAU,CAAC,eAAe,EAAE;KAC5D,CAAC,CACF,CAAC;AAAA,CACF","sourcesContent":["import { PROTOCOL_VERSION, type RuntimeAction, type RuntimeDecision, type RuntimeDecisionInput } from \"./types.ts\";\nimport { parseEvaluationResult, parseRuntimeDecision } from \"./validation.ts\";\n\nfunction policyAction(input: RuntimeDecisionInput): RuntimeAction {\n\tif (input.evaluation.semanticVerdict === \"pass\") return \"stop\";\n\treturn input.evaluation.semanticVerdict === \"fail\" ? input.policy.onFail : input.policy.onInconclusive;\n}\n\n/** Pure EvaluationResult -> RuntimeDecision reduction. */\nexport function reduceRuntimeDecision(input: RuntimeDecisionInput): RuntimeDecision {\n\tparseEvaluationResult(input.evaluation);\n\treturn parseRuntimeDecision(\n\t\tObject.freeze({\n\t\t\tschemaVersion: PROTOCOL_VERSION,\n\t\t\tdecisionId: input.decisionId,\n\t\t\ttaskId: input.evaluation.taskId,\n\t\t\tattemptId: input.evaluation.attemptId,\n\t\t\tevaluationId: input.evaluation.evaluationId,\n\t\t\tdecidedAt: input.decidedAt,\n\t\t\taction: policyAction(input),\n\t\t\treasonCode: `evaluation.${input.evaluation.semanticVerdict}`,\n\t\t}),\n\t);\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type EvaluationInput, type EvaluationResult } from "./types.ts";
|
|
2
|
+
export declare class ProtocolInvariantError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** Pure TaskSpec -> Observation -> Evaluation reduction. */
|
|
6
|
+
export declare function evaluateTask(input: EvaluationInput): EvaluationResult;
|
|
7
|
+
//# sourceMappingURL=evaluation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluation.d.ts","sourceRoot":"","sources":["../src/evaluation.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,eAAe,EACpB,KAAK,gBAAgB,EAMrB,MAAM,YAAY,CAAC;AASpB,qBAAa,sBAAuB,SAAQ,KAAK;IAChD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AAuHD,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAsCrE","sourcesContent":["import {\n\ttype ClaimCondition,\n\ttype ClaimEvaluation,\n\ttype ClaimResult,\n\ttype EvaluationInput,\n\ttype EvaluationResult,\n\ttype JsonValue,\n\ttype Observation,\n\tPROTOCOL_VERSION,\n\ttype SemanticVerdict,\n\ttype WaiverRecord,\n} from \"./types.ts\";\nimport {\n\tparseEvaluationResult,\n\tparseExecutionAttempt,\n\tparseObservation,\n\tparseTaskSpec,\n\tparseWaiverRecord,\n} from \"./validation.ts\";\n\nexport class ProtocolInvariantError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"ProtocolInvariantError\";\n\t}\n}\n\ninterface ConditionResult {\n\treadonly result: ClaimResult;\n\treadonly observationIds: readonly string[];\n}\n\nfunction isObject(value: JsonValue): value is { readonly [key: string]: JsonValue } {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction matchesExpected(actual: JsonValue | undefined, expected: JsonValue): boolean {\n\tif (Array.isArray(expected)) {\n\t\treturn (\n\t\t\tArray.isArray(actual) &&\n\t\t\tactual.length === expected.length &&\n\t\t\texpected.every((value, index) => matchesExpected(actual[index], value))\n\t\t);\n\t}\n\tif (isObject(expected)) {\n\t\treturn (\n\t\t\tactual !== undefined &&\n\t\t\tisObject(actual) &&\n\t\t\tObject.entries(expected).every(([key, value]) => matchesExpected(actual[key], value))\n\t\t);\n\t}\n\treturn Object.is(actual, expected);\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n\treturn [...new Set(values)];\n}\n\nfunction evaluateCondition(\n\tcondition: ClaimCondition,\n\tobservations: readonly Observation[],\n\tattemptId: string,\n): ConditionResult {\n\tif (condition.kind === \"observation\") {\n\t\tconst candidates = observations.filter(\n\t\t\t(observation) =>\n\t\t\t\tobservation.kind === condition.observationKind &&\n\t\t\t\t(condition.scope === \"task\" || observation.attemptId === attemptId),\n\t\t);\n\t\tif (candidates.length === 0) return { result: \"inconclusive\", observationIds: [] };\n\t\tconst matching = candidates.filter((observation) => matchesExpected(observation.facts, condition.facts));\n\t\treturn matching.length > 0\n\t\t\t? { result: \"satisfied\", observationIds: matching.map(({ observationId }) => observationId) }\n\t\t\t: { result: \"violated\", observationIds: candidates.map(({ observationId }) => observationId) };\n\t}\n\n\tif (condition.kind === \"not\") {\n\t\tconst child = evaluateCondition(condition.condition, observations, attemptId);\n\t\treturn {\n\t\t\tresult: child.result === \"satisfied\" ? \"violated\" : child.result === \"violated\" ? \"satisfied\" : \"inconclusive\",\n\t\t\tobservationIds: child.observationIds,\n\t\t};\n\t}\n\n\tconst children = condition.conditions.map((child) => evaluateCondition(child, observations, attemptId));\n\tif (condition.kind === \"all\") {\n\t\tconst result = children.some((child) => child.result === \"violated\")\n\t\t\t? \"violated\"\n\t\t\t: children.some((child) => child.result === \"inconclusive\")\n\t\t\t\t? \"inconclusive\"\n\t\t\t\t: \"satisfied\";\n\t\treturn { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };\n\t}\n\tconst result = children.some((child) => child.result === \"satisfied\")\n\t\t? \"satisfied\"\n\t\t: children.every((child) => child.result === \"violated\")\n\t\t\t? \"violated\"\n\t\t\t: \"inconclusive\";\n\treturn { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };\n}\n\nfunction reasonCode(result: ClaimResult): ClaimEvaluation[\"reasonCode\"] {\n\tif (result === \"satisfied\") return \"claim.satisfied\";\n\tif (result === \"violated\") return \"claim.violated\";\n\treturn \"claim.observation_missing\";\n}\n\nfunction validateWaivers(input: EvaluationInput, waivers: readonly WaiverRecord[]): ReadonlyMap<string, WaiverRecord> {\n\tconst claims = new Map(input.taskSpec.claims.map((claim) => [claim.claimId, claim]));\n\tconst byClaim = new Map<string, WaiverRecord>();\n\tfor (const waiver of waivers) {\n\t\tparseWaiverRecord(waiver);\n\t\tif (waiver.scope.taskId !== input.taskSpec.taskId) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} targets task ${waiver.scope.taskId}`);\n\t\t}\n\t\tconst claim = claims.get(waiver.scope.claimId);\n\t\tif (!claim) throw new ProtocolInvariantError(`${waiver.waiverId} targets unknown claim ${waiver.scope.claimId}`);\n\t\tif (claim.requirement !== \"required\") {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} cannot waive advisory claim ${claim.claimId}`);\n\t\t}\n\t\tif (waiver.scope.attemptId !== undefined && waiver.scope.attemptId !== input.attempt.attemptId) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} targets attempt ${waiver.scope.attemptId}`);\n\t\t}\n\t\tif (waiver.approvedAt > input.evaluatedAt) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} was approved after evaluation`);\n\t\t}\n\t\tif (waiver.expiresAt !== undefined && waiver.expiresAt <= input.evaluatedAt) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} is expired`);\n\t\t}\n\t\tif (byClaim.has(claim.claimId))\n\t\t\tthrow new ProtocolInvariantError(`multiple waivers target claim ${claim.claimId}`);\n\t\tbyClaim.set(claim.claimId, waiver);\n\t}\n\treturn byClaim;\n}\n\nfunction reduceVerdict(claims: readonly ClaimEvaluation[]): SemanticVerdict {\n\tconst required = claims.filter((claim) => claim.requirement === \"required\" && claim.waiverId === undefined);\n\tif (required.length === 0) return claims.some((claim) => claim.requirement === \"required\") ? \"pass\" : \"inconclusive\";\n\tif (required.some((claim) => claim.result === \"violated\")) return \"fail\";\n\tif (required.some((claim) => claim.result === \"inconclusive\")) return \"inconclusive\";\n\treturn \"pass\";\n}\n\n/** Pure TaskSpec -> Observation -> Evaluation reduction. */\nexport function evaluateTask(input: EvaluationInput): EvaluationResult {\n\tparseTaskSpec(input.taskSpec);\n\tparseExecutionAttempt(input.attempt);\n\tif (input.attempt.taskId !== input.taskSpec.taskId) {\n\t\tthrow new ProtocolInvariantError(`${input.attempt.attemptId} targets task ${input.attempt.taskId}`);\n\t}\n\tfor (const observation of input.observations) {\n\t\tparseObservation(observation);\n\t\tif (observation.taskId !== input.taskSpec.taskId) {\n\t\t\tthrow new ProtocolInvariantError(`${observation.observationId} targets task ${observation.taskId}`);\n\t\t}\n\t}\n\tconst waivers = validateWaivers(input, input.waivers ?? []);\n\tconst claims = Object.freeze(\n\t\tinput.taskSpec.claims.map((claim): ClaimEvaluation => {\n\t\t\tconst evaluated = evaluateCondition(claim.condition, input.observations, input.attempt.attemptId);\n\t\t\tconst waiver = evaluated.result === \"satisfied\" ? undefined : waivers.get(claim.claimId);\n\t\t\treturn Object.freeze({\n\t\t\t\tclaimId: claim.claimId,\n\t\t\t\trequirement: claim.requirement,\n\t\t\t\tresult: evaluated.result,\n\t\t\t\treasonCode: reasonCode(evaluated.result),\n\t\t\t\tobservationIds: Object.freeze([...evaluated.observationIds]),\n\t\t\t\t...(waiver ? { waiverId: waiver.waiverId } : {}),\n\t\t\t});\n\t\t}),\n\t);\n\treturn parseEvaluationResult(\n\t\tObject.freeze({\n\t\t\tschemaVersion: PROTOCOL_VERSION,\n\t\t\tevaluationId: input.evaluationId,\n\t\t\ttaskId: input.taskSpec.taskId,\n\t\t\tattemptId: input.attempt.attemptId,\n\t\t\tevaluatedAt: input.evaluatedAt,\n\t\t\tclaims,\n\t\t\tsemanticVerdict: reduceVerdict(claims),\n\t\t}),\n\t);\n}\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { PROTOCOL_VERSION, } from "./types.js";
|
|
2
|
+
import { parseEvaluationResult, parseExecutionAttempt, parseObservation, parseTaskSpec, parseWaiverRecord, } from "./validation.js";
|
|
3
|
+
export class ProtocolInvariantError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "ProtocolInvariantError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function isObject(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function matchesExpected(actual, expected) {
|
|
13
|
+
if (Array.isArray(expected)) {
|
|
14
|
+
return (Array.isArray(actual) &&
|
|
15
|
+
actual.length === expected.length &&
|
|
16
|
+
expected.every((value, index) => matchesExpected(actual[index], value)));
|
|
17
|
+
}
|
|
18
|
+
if (isObject(expected)) {
|
|
19
|
+
return (actual !== undefined &&
|
|
20
|
+
isObject(actual) &&
|
|
21
|
+
Object.entries(expected).every(([key, value]) => matchesExpected(actual[key], value)));
|
|
22
|
+
}
|
|
23
|
+
return Object.is(actual, expected);
|
|
24
|
+
}
|
|
25
|
+
function unique(values) {
|
|
26
|
+
return [...new Set(values)];
|
|
27
|
+
}
|
|
28
|
+
function evaluateCondition(condition, observations, attemptId) {
|
|
29
|
+
if (condition.kind === "observation") {
|
|
30
|
+
const candidates = observations.filter((observation) => observation.kind === condition.observationKind &&
|
|
31
|
+
(condition.scope === "task" || observation.attemptId === attemptId));
|
|
32
|
+
if (candidates.length === 0)
|
|
33
|
+
return { result: "inconclusive", observationIds: [] };
|
|
34
|
+
const matching = candidates.filter((observation) => matchesExpected(observation.facts, condition.facts));
|
|
35
|
+
return matching.length > 0
|
|
36
|
+
? { result: "satisfied", observationIds: matching.map(({ observationId }) => observationId) }
|
|
37
|
+
: { result: "violated", observationIds: candidates.map(({ observationId }) => observationId) };
|
|
38
|
+
}
|
|
39
|
+
if (condition.kind === "not") {
|
|
40
|
+
const child = evaluateCondition(condition.condition, observations, attemptId);
|
|
41
|
+
return {
|
|
42
|
+
result: child.result === "satisfied" ? "violated" : child.result === "violated" ? "satisfied" : "inconclusive",
|
|
43
|
+
observationIds: child.observationIds,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const children = condition.conditions.map((child) => evaluateCondition(child, observations, attemptId));
|
|
47
|
+
if (condition.kind === "all") {
|
|
48
|
+
const result = children.some((child) => child.result === "violated")
|
|
49
|
+
? "violated"
|
|
50
|
+
: children.some((child) => child.result === "inconclusive")
|
|
51
|
+
? "inconclusive"
|
|
52
|
+
: "satisfied";
|
|
53
|
+
return { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };
|
|
54
|
+
}
|
|
55
|
+
const result = children.some((child) => child.result === "satisfied")
|
|
56
|
+
? "satisfied"
|
|
57
|
+
: children.every((child) => child.result === "violated")
|
|
58
|
+
? "violated"
|
|
59
|
+
: "inconclusive";
|
|
60
|
+
return { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };
|
|
61
|
+
}
|
|
62
|
+
function reasonCode(result) {
|
|
63
|
+
if (result === "satisfied")
|
|
64
|
+
return "claim.satisfied";
|
|
65
|
+
if (result === "violated")
|
|
66
|
+
return "claim.violated";
|
|
67
|
+
return "claim.observation_missing";
|
|
68
|
+
}
|
|
69
|
+
function validateWaivers(input, waivers) {
|
|
70
|
+
const claims = new Map(input.taskSpec.claims.map((claim) => [claim.claimId, claim]));
|
|
71
|
+
const byClaim = new Map();
|
|
72
|
+
for (const waiver of waivers) {
|
|
73
|
+
parseWaiverRecord(waiver);
|
|
74
|
+
if (waiver.scope.taskId !== input.taskSpec.taskId) {
|
|
75
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} targets task ${waiver.scope.taskId}`);
|
|
76
|
+
}
|
|
77
|
+
const claim = claims.get(waiver.scope.claimId);
|
|
78
|
+
if (!claim)
|
|
79
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} targets unknown claim ${waiver.scope.claimId}`);
|
|
80
|
+
if (claim.requirement !== "required") {
|
|
81
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} cannot waive advisory claim ${claim.claimId}`);
|
|
82
|
+
}
|
|
83
|
+
if (waiver.scope.attemptId !== undefined && waiver.scope.attemptId !== input.attempt.attemptId) {
|
|
84
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} targets attempt ${waiver.scope.attemptId}`);
|
|
85
|
+
}
|
|
86
|
+
if (waiver.approvedAt > input.evaluatedAt) {
|
|
87
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} was approved after evaluation`);
|
|
88
|
+
}
|
|
89
|
+
if (waiver.expiresAt !== undefined && waiver.expiresAt <= input.evaluatedAt) {
|
|
90
|
+
throw new ProtocolInvariantError(`${waiver.waiverId} is expired`);
|
|
91
|
+
}
|
|
92
|
+
if (byClaim.has(claim.claimId))
|
|
93
|
+
throw new ProtocolInvariantError(`multiple waivers target claim ${claim.claimId}`);
|
|
94
|
+
byClaim.set(claim.claimId, waiver);
|
|
95
|
+
}
|
|
96
|
+
return byClaim;
|
|
97
|
+
}
|
|
98
|
+
function reduceVerdict(claims) {
|
|
99
|
+
const required = claims.filter((claim) => claim.requirement === "required" && claim.waiverId === undefined);
|
|
100
|
+
if (required.length === 0)
|
|
101
|
+
return claims.some((claim) => claim.requirement === "required") ? "pass" : "inconclusive";
|
|
102
|
+
if (required.some((claim) => claim.result === "violated"))
|
|
103
|
+
return "fail";
|
|
104
|
+
if (required.some((claim) => claim.result === "inconclusive"))
|
|
105
|
+
return "inconclusive";
|
|
106
|
+
return "pass";
|
|
107
|
+
}
|
|
108
|
+
/** Pure TaskSpec -> Observation -> Evaluation reduction. */
|
|
109
|
+
export function evaluateTask(input) {
|
|
110
|
+
parseTaskSpec(input.taskSpec);
|
|
111
|
+
parseExecutionAttempt(input.attempt);
|
|
112
|
+
if (input.attempt.taskId !== input.taskSpec.taskId) {
|
|
113
|
+
throw new ProtocolInvariantError(`${input.attempt.attemptId} targets task ${input.attempt.taskId}`);
|
|
114
|
+
}
|
|
115
|
+
for (const observation of input.observations) {
|
|
116
|
+
parseObservation(observation);
|
|
117
|
+
if (observation.taskId !== input.taskSpec.taskId) {
|
|
118
|
+
throw new ProtocolInvariantError(`${observation.observationId} targets task ${observation.taskId}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const waivers = validateWaivers(input, input.waivers ?? []);
|
|
122
|
+
const claims = Object.freeze(input.taskSpec.claims.map((claim) => {
|
|
123
|
+
const evaluated = evaluateCondition(claim.condition, input.observations, input.attempt.attemptId);
|
|
124
|
+
const waiver = evaluated.result === "satisfied" ? undefined : waivers.get(claim.claimId);
|
|
125
|
+
return Object.freeze({
|
|
126
|
+
claimId: claim.claimId,
|
|
127
|
+
requirement: claim.requirement,
|
|
128
|
+
result: evaluated.result,
|
|
129
|
+
reasonCode: reasonCode(evaluated.result),
|
|
130
|
+
observationIds: Object.freeze([...evaluated.observationIds]),
|
|
131
|
+
...(waiver ? { waiverId: waiver.waiverId } : {}),
|
|
132
|
+
});
|
|
133
|
+
}));
|
|
134
|
+
return parseEvaluationResult(Object.freeze({
|
|
135
|
+
schemaVersion: PROTOCOL_VERSION,
|
|
136
|
+
evaluationId: input.evaluationId,
|
|
137
|
+
taskId: input.taskSpec.taskId,
|
|
138
|
+
attemptId: input.attempt.attemptId,
|
|
139
|
+
evaluatedAt: input.evaluatedAt,
|
|
140
|
+
claims,
|
|
141
|
+
semanticVerdict: reduceVerdict(claims),
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=evaluation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluation.js","sourceRoot":"","sources":["../src/evaluation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ClaimCondition,\n\ttype ClaimEvaluation,\n\ttype ClaimResult,\n\ttype EvaluationInput,\n\ttype EvaluationResult,\n\ttype JsonValue,\n\ttype Observation,\n\tPROTOCOL_VERSION,\n\ttype SemanticVerdict,\n\ttype WaiverRecord,\n} from \"./types.ts\";\nimport {\n\tparseEvaluationResult,\n\tparseExecutionAttempt,\n\tparseObservation,\n\tparseTaskSpec,\n\tparseWaiverRecord,\n} from \"./validation.ts\";\n\nexport class ProtocolInvariantError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"ProtocolInvariantError\";\n\t}\n}\n\ninterface ConditionResult {\n\treadonly result: ClaimResult;\n\treadonly observationIds: readonly string[];\n}\n\nfunction isObject(value: JsonValue): value is { readonly [key: string]: JsonValue } {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction matchesExpected(actual: JsonValue | undefined, expected: JsonValue): boolean {\n\tif (Array.isArray(expected)) {\n\t\treturn (\n\t\t\tArray.isArray(actual) &&\n\t\t\tactual.length === expected.length &&\n\t\t\texpected.every((value, index) => matchesExpected(actual[index], value))\n\t\t);\n\t}\n\tif (isObject(expected)) {\n\t\treturn (\n\t\t\tactual !== undefined &&\n\t\t\tisObject(actual) &&\n\t\t\tObject.entries(expected).every(([key, value]) => matchesExpected(actual[key], value))\n\t\t);\n\t}\n\treturn Object.is(actual, expected);\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n\treturn [...new Set(values)];\n}\n\nfunction evaluateCondition(\n\tcondition: ClaimCondition,\n\tobservations: readonly Observation[],\n\tattemptId: string,\n): ConditionResult {\n\tif (condition.kind === \"observation\") {\n\t\tconst candidates = observations.filter(\n\t\t\t(observation) =>\n\t\t\t\tobservation.kind === condition.observationKind &&\n\t\t\t\t(condition.scope === \"task\" || observation.attemptId === attemptId),\n\t\t);\n\t\tif (candidates.length === 0) return { result: \"inconclusive\", observationIds: [] };\n\t\tconst matching = candidates.filter((observation) => matchesExpected(observation.facts, condition.facts));\n\t\treturn matching.length > 0\n\t\t\t? { result: \"satisfied\", observationIds: matching.map(({ observationId }) => observationId) }\n\t\t\t: { result: \"violated\", observationIds: candidates.map(({ observationId }) => observationId) };\n\t}\n\n\tif (condition.kind === \"not\") {\n\t\tconst child = evaluateCondition(condition.condition, observations, attemptId);\n\t\treturn {\n\t\t\tresult: child.result === \"satisfied\" ? \"violated\" : child.result === \"violated\" ? \"satisfied\" : \"inconclusive\",\n\t\t\tobservationIds: child.observationIds,\n\t\t};\n\t}\n\n\tconst children = condition.conditions.map((child) => evaluateCondition(child, observations, attemptId));\n\tif (condition.kind === \"all\") {\n\t\tconst result = children.some((child) => child.result === \"violated\")\n\t\t\t? \"violated\"\n\t\t\t: children.some((child) => child.result === \"inconclusive\")\n\t\t\t\t? \"inconclusive\"\n\t\t\t\t: \"satisfied\";\n\t\treturn { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };\n\t}\n\tconst result = children.some((child) => child.result === \"satisfied\")\n\t\t? \"satisfied\"\n\t\t: children.every((child) => child.result === \"violated\")\n\t\t\t? \"violated\"\n\t\t\t: \"inconclusive\";\n\treturn { result, observationIds: unique(children.flatMap(({ observationIds }) => observationIds)) };\n}\n\nfunction reasonCode(result: ClaimResult): ClaimEvaluation[\"reasonCode\"] {\n\tif (result === \"satisfied\") return \"claim.satisfied\";\n\tif (result === \"violated\") return \"claim.violated\";\n\treturn \"claim.observation_missing\";\n}\n\nfunction validateWaivers(input: EvaluationInput, waivers: readonly WaiverRecord[]): ReadonlyMap<string, WaiverRecord> {\n\tconst claims = new Map(input.taskSpec.claims.map((claim) => [claim.claimId, claim]));\n\tconst byClaim = new Map<string, WaiverRecord>();\n\tfor (const waiver of waivers) {\n\t\tparseWaiverRecord(waiver);\n\t\tif (waiver.scope.taskId !== input.taskSpec.taskId) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} targets task ${waiver.scope.taskId}`);\n\t\t}\n\t\tconst claim = claims.get(waiver.scope.claimId);\n\t\tif (!claim) throw new ProtocolInvariantError(`${waiver.waiverId} targets unknown claim ${waiver.scope.claimId}`);\n\t\tif (claim.requirement !== \"required\") {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} cannot waive advisory claim ${claim.claimId}`);\n\t\t}\n\t\tif (waiver.scope.attemptId !== undefined && waiver.scope.attemptId !== input.attempt.attemptId) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} targets attempt ${waiver.scope.attemptId}`);\n\t\t}\n\t\tif (waiver.approvedAt > input.evaluatedAt) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} was approved after evaluation`);\n\t\t}\n\t\tif (waiver.expiresAt !== undefined && waiver.expiresAt <= input.evaluatedAt) {\n\t\t\tthrow new ProtocolInvariantError(`${waiver.waiverId} is expired`);\n\t\t}\n\t\tif (byClaim.has(claim.claimId))\n\t\t\tthrow new ProtocolInvariantError(`multiple waivers target claim ${claim.claimId}`);\n\t\tbyClaim.set(claim.claimId, waiver);\n\t}\n\treturn byClaim;\n}\n\nfunction reduceVerdict(claims: readonly ClaimEvaluation[]): SemanticVerdict {\n\tconst required = claims.filter((claim) => claim.requirement === \"required\" && claim.waiverId === undefined);\n\tif (required.length === 0) return claims.some((claim) => claim.requirement === \"required\") ? \"pass\" : \"inconclusive\";\n\tif (required.some((claim) => claim.result === \"violated\")) return \"fail\";\n\tif (required.some((claim) => claim.result === \"inconclusive\")) return \"inconclusive\";\n\treturn \"pass\";\n}\n\n/** Pure TaskSpec -> Observation -> Evaluation reduction. */\nexport function evaluateTask(input: EvaluationInput): EvaluationResult {\n\tparseTaskSpec(input.taskSpec);\n\tparseExecutionAttempt(input.attempt);\n\tif (input.attempt.taskId !== input.taskSpec.taskId) {\n\t\tthrow new ProtocolInvariantError(`${input.attempt.attemptId} targets task ${input.attempt.taskId}`);\n\t}\n\tfor (const observation of input.observations) {\n\t\tparseObservation(observation);\n\t\tif (observation.taskId !== input.taskSpec.taskId) {\n\t\t\tthrow new ProtocolInvariantError(`${observation.observationId} targets task ${observation.taskId}`);\n\t\t}\n\t}\n\tconst waivers = validateWaivers(input, input.waivers ?? []);\n\tconst claims = Object.freeze(\n\t\tinput.taskSpec.claims.map((claim): ClaimEvaluation => {\n\t\t\tconst evaluated = evaluateCondition(claim.condition, input.observations, input.attempt.attemptId);\n\t\t\tconst waiver = evaluated.result === \"satisfied\" ? undefined : waivers.get(claim.claimId);\n\t\t\treturn Object.freeze({\n\t\t\t\tclaimId: claim.claimId,\n\t\t\t\trequirement: claim.requirement,\n\t\t\t\tresult: evaluated.result,\n\t\t\t\treasonCode: reasonCode(evaluated.result),\n\t\t\t\tobservationIds: Object.freeze([...evaluated.observationIds]),\n\t\t\t\t...(waiver ? { waiverId: waiver.waiverId } : {}),\n\t\t\t});\n\t\t}),\n\t);\n\treturn parseEvaluationResult(\n\t\tObject.freeze({\n\t\t\tschemaVersion: PROTOCOL_VERSION,\n\t\t\tevaluationId: input.evaluationId,\n\t\t\ttaskId: input.taskSpec.taskId,\n\t\t\tattemptId: input.attempt.attemptId,\n\t\t\tevaluatedAt: input.evaluatedAt,\n\t\t\tclaims,\n\t\t\tsemanticVerdict: reduceVerdict(claims),\n\t\t}),\n\t);\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { reduceRuntimeDecision } from "./decision.ts";
|
|
2
|
+
export { evaluateTask, ProtocolInvariantError } from "./evaluation.ts";
|
|
3
|
+
export type { AllCondition, AnyCondition, AttemptExecutor, AttemptOutcome, AttemptTrigger, ClaimCondition, ClaimEvaluation, ClaimPredicate, ClaimReasonCode, ClaimResult, EvaluationInput, EvaluationResult, ExecutionAttempt, JsonObject, JsonPrimitive, JsonValue, NotCondition, Observation, ObservationCondition, ProtocolVersion, RequirementLevel, RuntimeAction, RuntimeDecision, RuntimeDecisionInput, RuntimeDecisionPolicy, RuntimeDecisionReason, SemanticVerdict, TaskSpec, WaiverRecord, } from "./types.ts";
|
|
4
|
+
export { PROTOCOL_VERSION } from "./types.ts";
|
|
5
|
+
export { ProtocolValidationError, parseEvaluationResult, parseExecutionAttempt, parseObservation, parseRuntimeDecision, parseTaskSpec, parseWaiverRecord, } from "./validation.ts";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACvE,YAAY,EACX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,QAAQ,EACR,YAAY,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACN,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GACjB,MAAM,iBAAiB,CAAC","sourcesContent":["export { reduceRuntimeDecision } from \"./decision.ts\";\nexport { evaluateTask, ProtocolInvariantError } from \"./evaluation.ts\";\nexport type {\n\tAllCondition,\n\tAnyCondition,\n\tAttemptExecutor,\n\tAttemptOutcome,\n\tAttemptTrigger,\n\tClaimCondition,\n\tClaimEvaluation,\n\tClaimPredicate,\n\tClaimReasonCode,\n\tClaimResult,\n\tEvaluationInput,\n\tEvaluationResult,\n\tExecutionAttempt,\n\tJsonObject,\n\tJsonPrimitive,\n\tJsonValue,\n\tNotCondition,\n\tObservation,\n\tObservationCondition,\n\tProtocolVersion,\n\tRequirementLevel,\n\tRuntimeAction,\n\tRuntimeDecision,\n\tRuntimeDecisionInput,\n\tRuntimeDecisionPolicy,\n\tRuntimeDecisionReason,\n\tSemanticVerdict,\n\tTaskSpec,\n\tWaiverRecord,\n} from \"./types.ts\";\nexport { PROTOCOL_VERSION } from \"./types.ts\";\nexport {\n\tProtocolValidationError,\n\tparseEvaluationResult,\n\tparseExecutionAttempt,\n\tparseObservation,\n\tparseRuntimeDecision,\n\tparseTaskSpec,\n\tparseWaiverRecord,\n} from \"./validation.ts\";\n"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { reduceRuntimeDecision } from "./decision.js";
|
|
2
|
+
export { evaluateTask, ProtocolInvariantError } from "./evaluation.js";
|
|
3
|
+
export { PROTOCOL_VERSION } from "./types.js";
|
|
4
|
+
export { ProtocolValidationError, parseEvaluationResult, parseExecutionAttempt, parseObservation, parseRuntimeDecision, parseTaskSpec, parseWaiverRecord, } from "./validation.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAgCvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACN,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GACjB,MAAM,iBAAiB,CAAC","sourcesContent":["export { reduceRuntimeDecision } from \"./decision.ts\";\nexport { evaluateTask, ProtocolInvariantError } from \"./evaluation.ts\";\nexport type {\n\tAllCondition,\n\tAnyCondition,\n\tAttemptExecutor,\n\tAttemptOutcome,\n\tAttemptTrigger,\n\tClaimCondition,\n\tClaimEvaluation,\n\tClaimPredicate,\n\tClaimReasonCode,\n\tClaimResult,\n\tEvaluationInput,\n\tEvaluationResult,\n\tExecutionAttempt,\n\tJsonObject,\n\tJsonPrimitive,\n\tJsonValue,\n\tNotCondition,\n\tObservation,\n\tObservationCondition,\n\tProtocolVersion,\n\tRequirementLevel,\n\tRuntimeAction,\n\tRuntimeDecision,\n\tRuntimeDecisionInput,\n\tRuntimeDecisionPolicy,\n\tRuntimeDecisionReason,\n\tSemanticVerdict,\n\tTaskSpec,\n\tWaiverRecord,\n} from \"./types.ts\";\nexport { PROTOCOL_VERSION } from \"./types.ts\";\nexport {\n\tProtocolValidationError,\n\tparseEvaluationResult,\n\tparseExecutionAttempt,\n\tparseObservation,\n\tparseRuntimeDecision,\n\tparseTaskSpec,\n\tparseWaiverRecord,\n} from \"./validation.ts\";\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export declare const PROTOCOL_VERSION: "omk.run.v1";
|
|
2
|
+
export type ProtocolVersion = typeof PROTOCOL_VERSION;
|
|
3
|
+
export type JsonPrimitive = boolean | number | string | null;
|
|
4
|
+
export type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];
|
|
5
|
+
export interface JsonObject {
|
|
6
|
+
readonly [key: string]: JsonValue;
|
|
7
|
+
}
|
|
8
|
+
export type RequirementLevel = "required" | "advisory";
|
|
9
|
+
export type SemanticVerdict = "pass" | "fail" | "inconclusive";
|
|
10
|
+
export type ClaimResult = "satisfied" | "violated" | "inconclusive";
|
|
11
|
+
export type RuntimeAction = "continue" | "retry" | "failover" | "stop";
|
|
12
|
+
export interface ObservationCondition {
|
|
13
|
+
readonly kind: "observation";
|
|
14
|
+
readonly observationKind: string;
|
|
15
|
+
readonly scope: "attempt" | "task";
|
|
16
|
+
readonly facts: JsonObject;
|
|
17
|
+
}
|
|
18
|
+
export interface AllCondition {
|
|
19
|
+
readonly kind: "all";
|
|
20
|
+
readonly conditions: readonly ClaimCondition[];
|
|
21
|
+
}
|
|
22
|
+
export interface AnyCondition {
|
|
23
|
+
readonly kind: "any";
|
|
24
|
+
readonly conditions: readonly ClaimCondition[];
|
|
25
|
+
}
|
|
26
|
+
export interface NotCondition {
|
|
27
|
+
readonly kind: "not";
|
|
28
|
+
readonly condition: ClaimCondition;
|
|
29
|
+
}
|
|
30
|
+
export type ClaimCondition = ObservationCondition | AllCondition | AnyCondition | NotCondition;
|
|
31
|
+
export interface ClaimPredicate {
|
|
32
|
+
readonly claimId: string;
|
|
33
|
+
readonly statement: string;
|
|
34
|
+
readonly requirement: RequirementLevel;
|
|
35
|
+
readonly condition: ClaimCondition;
|
|
36
|
+
}
|
|
37
|
+
export interface TaskSpec {
|
|
38
|
+
readonly schemaVersion: ProtocolVersion;
|
|
39
|
+
readonly taskId: string;
|
|
40
|
+
readonly goal: string;
|
|
41
|
+
readonly createdAt: string;
|
|
42
|
+
readonly claims: readonly ClaimPredicate[];
|
|
43
|
+
}
|
|
44
|
+
export type AttemptTrigger = "initial" | "retry" | "failover" | "resume";
|
|
45
|
+
export interface AttemptExecutor {
|
|
46
|
+
readonly kind: string;
|
|
47
|
+
readonly provider?: string;
|
|
48
|
+
readonly model?: string;
|
|
49
|
+
}
|
|
50
|
+
export type AttemptOutcome = {
|
|
51
|
+
readonly kind: "completed";
|
|
52
|
+
} | {
|
|
53
|
+
readonly kind: "failed";
|
|
54
|
+
readonly code: string;
|
|
55
|
+
readonly message?: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly kind: "cancelled";
|
|
58
|
+
readonly code: string;
|
|
59
|
+
};
|
|
60
|
+
/** One completed execution. Retry and failover counts are derived from these records. */
|
|
61
|
+
export interface ExecutionAttempt {
|
|
62
|
+
readonly schemaVersion: ProtocolVersion;
|
|
63
|
+
readonly attemptId: string;
|
|
64
|
+
readonly taskId: string;
|
|
65
|
+
readonly sequence: number;
|
|
66
|
+
readonly trigger: AttemptTrigger;
|
|
67
|
+
readonly previousAttemptId?: string;
|
|
68
|
+
readonly startedAt: string;
|
|
69
|
+
readonly finishedAt: string;
|
|
70
|
+
readonly executor: AttemptExecutor;
|
|
71
|
+
readonly outcome: AttemptOutcome;
|
|
72
|
+
}
|
|
73
|
+
/** Immutable execution facts. Semantic pass/fail belongs only in ClaimEvaluation. */
|
|
74
|
+
export interface Observation {
|
|
75
|
+
readonly schemaVersion: ProtocolVersion;
|
|
76
|
+
readonly observationId: string;
|
|
77
|
+
readonly taskId: string;
|
|
78
|
+
readonly attemptId: string;
|
|
79
|
+
readonly observedAt: string;
|
|
80
|
+
readonly kind: string;
|
|
81
|
+
readonly source: {
|
|
82
|
+
readonly kind: string;
|
|
83
|
+
readonly id: string;
|
|
84
|
+
};
|
|
85
|
+
readonly facts: JsonObject;
|
|
86
|
+
readonly evidenceRefs: readonly string[];
|
|
87
|
+
}
|
|
88
|
+
export interface WaiverRecord {
|
|
89
|
+
readonly schemaVersion: ProtocolVersion;
|
|
90
|
+
readonly waiverId: string;
|
|
91
|
+
readonly scope: {
|
|
92
|
+
readonly taskId: string;
|
|
93
|
+
readonly claimId: string;
|
|
94
|
+
readonly attemptId?: string;
|
|
95
|
+
};
|
|
96
|
+
readonly approvedBy: string;
|
|
97
|
+
readonly approvedAt: string;
|
|
98
|
+
readonly expiresAt?: string;
|
|
99
|
+
readonly rationale: string;
|
|
100
|
+
readonly evidenceRefs: readonly string[];
|
|
101
|
+
}
|
|
102
|
+
export type ClaimReasonCode = "claim.satisfied" | "claim.violated" | "claim.observation_missing";
|
|
103
|
+
export interface ClaimEvaluation {
|
|
104
|
+
readonly claimId: string;
|
|
105
|
+
readonly requirement: RequirementLevel;
|
|
106
|
+
readonly result: ClaimResult;
|
|
107
|
+
readonly reasonCode: ClaimReasonCode;
|
|
108
|
+
readonly observationIds: readonly string[];
|
|
109
|
+
readonly waiverId?: string;
|
|
110
|
+
}
|
|
111
|
+
export interface EvaluationResult {
|
|
112
|
+
readonly schemaVersion: ProtocolVersion;
|
|
113
|
+
readonly evaluationId: string;
|
|
114
|
+
readonly taskId: string;
|
|
115
|
+
readonly attemptId: string;
|
|
116
|
+
readonly evaluatedAt: string;
|
|
117
|
+
readonly claims: readonly ClaimEvaluation[];
|
|
118
|
+
readonly semanticVerdict: SemanticVerdict;
|
|
119
|
+
}
|
|
120
|
+
export interface EvaluationInput {
|
|
121
|
+
readonly evaluationId: string;
|
|
122
|
+
readonly evaluatedAt: string;
|
|
123
|
+
readonly taskSpec: TaskSpec;
|
|
124
|
+
readonly attempt: ExecutionAttempt;
|
|
125
|
+
readonly observations: readonly Observation[];
|
|
126
|
+
readonly waivers?: readonly WaiverRecord[];
|
|
127
|
+
}
|
|
128
|
+
export interface RuntimeDecisionPolicy {
|
|
129
|
+
readonly onFail: RuntimeAction;
|
|
130
|
+
readonly onInconclusive: RuntimeAction;
|
|
131
|
+
}
|
|
132
|
+
export type RuntimeDecisionReason = "evaluation.pass" | "evaluation.fail" | "evaluation.inconclusive";
|
|
133
|
+
export interface RuntimeDecision {
|
|
134
|
+
readonly schemaVersion: ProtocolVersion;
|
|
135
|
+
readonly decisionId: string;
|
|
136
|
+
readonly taskId: string;
|
|
137
|
+
readonly attemptId: string;
|
|
138
|
+
readonly evaluationId: string;
|
|
139
|
+
readonly decidedAt: string;
|
|
140
|
+
readonly action: RuntimeAction;
|
|
141
|
+
readonly reasonCode: RuntimeDecisionReason;
|
|
142
|
+
}
|
|
143
|
+
export interface RuntimeDecisionInput {
|
|
144
|
+
readonly decisionId: string;
|
|
145
|
+
readonly decidedAt: string;
|
|
146
|
+
readonly evaluation: EvaluationResult;
|
|
147
|
+
readonly policy: RuntimeDecisionPolicy;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["export const PROTOCOL_VERSION = \"omk.run.v1\" as const;\n\nexport type ProtocolVersion = typeof PROTOCOL_VERSION;\nexport type JsonPrimitive = boolean | number | string | null;\nexport type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];\nexport interface JsonObject {\n\treadonly [key: string]: JsonValue;\n}\n\nexport type RequirementLevel = \"required\" | \"advisory\";\nexport type SemanticVerdict = \"pass\" | \"fail\" | \"inconclusive\";\nexport type ClaimResult = \"satisfied\" | \"violated\" | \"inconclusive\";\nexport type RuntimeAction = \"continue\" | \"retry\" | \"failover\" | \"stop\";\n\nexport interface ObservationCondition {\n\treadonly kind: \"observation\";\n\treadonly observationKind: string;\n\treadonly scope: \"attempt\" | \"task\";\n\treadonly facts: JsonObject;\n}\n\nexport interface AllCondition {\n\treadonly kind: \"all\";\n\treadonly conditions: readonly ClaimCondition[];\n}\n\nexport interface AnyCondition {\n\treadonly kind: \"any\";\n\treadonly conditions: readonly ClaimCondition[];\n}\n\nexport interface NotCondition {\n\treadonly kind: \"not\";\n\treadonly condition: ClaimCondition;\n}\n\nexport type ClaimCondition = ObservationCondition | AllCondition | AnyCondition | NotCondition;\n\nexport interface ClaimPredicate {\n\treadonly claimId: string;\n\treadonly statement: string;\n\treadonly requirement: RequirementLevel;\n\treadonly condition: ClaimCondition;\n}\n\nexport interface TaskSpec {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly taskId: string;\n\treadonly goal: string;\n\treadonly createdAt: string;\n\treadonly claims: readonly ClaimPredicate[];\n}\n\nexport type AttemptTrigger = \"initial\" | \"retry\" | \"failover\" | \"resume\";\n\nexport interface AttemptExecutor {\n\treadonly kind: string;\n\treadonly provider?: string;\n\treadonly model?: string;\n}\n\nexport type AttemptOutcome =\n\t| { readonly kind: \"completed\" }\n\t| { readonly kind: \"failed\"; readonly code: string; readonly message?: string }\n\t| { readonly kind: \"cancelled\"; readonly code: string };\n\n/** One completed execution. Retry and failover counts are derived from these records. */\nexport interface ExecutionAttempt {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly attemptId: string;\n\treadonly taskId: string;\n\treadonly sequence: number;\n\treadonly trigger: AttemptTrigger;\n\treadonly previousAttemptId?: string;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly executor: AttemptExecutor;\n\treadonly outcome: AttemptOutcome;\n}\n\n/** Immutable execution facts. Semantic pass/fail belongs only in ClaimEvaluation. */\nexport interface Observation {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly observationId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly observedAt: string;\n\treadonly kind: string;\n\treadonly source: {\n\t\treadonly kind: string;\n\t\treadonly id: string;\n\t};\n\treadonly facts: JsonObject;\n\treadonly evidenceRefs: readonly string[];\n}\n\nexport interface WaiverRecord {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly waiverId: string;\n\treadonly scope: {\n\t\treadonly taskId: string;\n\t\treadonly claimId: string;\n\t\treadonly attemptId?: string;\n\t};\n\treadonly approvedBy: string;\n\treadonly approvedAt: string;\n\treadonly expiresAt?: string;\n\treadonly rationale: string;\n\treadonly evidenceRefs: readonly string[];\n}\n\nexport type ClaimReasonCode = \"claim.satisfied\" | \"claim.violated\" | \"claim.observation_missing\";\n\nexport interface ClaimEvaluation {\n\treadonly claimId: string;\n\treadonly requirement: RequirementLevel;\n\treadonly result: ClaimResult;\n\treadonly reasonCode: ClaimReasonCode;\n\treadonly observationIds: readonly string[];\n\treadonly waiverId?: string;\n}\n\nexport interface EvaluationResult {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly evaluationId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly evaluatedAt: string;\n\treadonly claims: readonly ClaimEvaluation[];\n\treadonly semanticVerdict: SemanticVerdict;\n}\n\nexport interface EvaluationInput {\n\treadonly evaluationId: string;\n\treadonly evaluatedAt: string;\n\treadonly taskSpec: TaskSpec;\n\treadonly attempt: ExecutionAttempt;\n\treadonly observations: readonly Observation[];\n\treadonly waivers?: readonly WaiverRecord[];\n}\n\nexport interface RuntimeDecisionPolicy {\n\treadonly onFail: RuntimeAction;\n\treadonly onInconclusive: RuntimeAction;\n}\n\nexport type RuntimeDecisionReason = \"evaluation.pass\" | \"evaluation.fail\" | \"evaluation.inconclusive\";\n\nexport interface RuntimeDecision {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly decisionId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly evaluationId: string;\n\treadonly decidedAt: string;\n\treadonly action: RuntimeAction;\n\treadonly reasonCode: RuntimeDecisionReason;\n}\n\nexport interface RuntimeDecisionInput {\n\treadonly decisionId: string;\n\treadonly decidedAt: string;\n\treadonly evaluation: EvaluationResult;\n\treadonly policy: RuntimeDecisionPolicy;\n}\n"]}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAqB,CAAC","sourcesContent":["export const PROTOCOL_VERSION = \"omk.run.v1\" as const;\n\nexport type ProtocolVersion = typeof PROTOCOL_VERSION;\nexport type JsonPrimitive = boolean | number | string | null;\nexport type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];\nexport interface JsonObject {\n\treadonly [key: string]: JsonValue;\n}\n\nexport type RequirementLevel = \"required\" | \"advisory\";\nexport type SemanticVerdict = \"pass\" | \"fail\" | \"inconclusive\";\nexport type ClaimResult = \"satisfied\" | \"violated\" | \"inconclusive\";\nexport type RuntimeAction = \"continue\" | \"retry\" | \"failover\" | \"stop\";\n\nexport interface ObservationCondition {\n\treadonly kind: \"observation\";\n\treadonly observationKind: string;\n\treadonly scope: \"attempt\" | \"task\";\n\treadonly facts: JsonObject;\n}\n\nexport interface AllCondition {\n\treadonly kind: \"all\";\n\treadonly conditions: readonly ClaimCondition[];\n}\n\nexport interface AnyCondition {\n\treadonly kind: \"any\";\n\treadonly conditions: readonly ClaimCondition[];\n}\n\nexport interface NotCondition {\n\treadonly kind: \"not\";\n\treadonly condition: ClaimCondition;\n}\n\nexport type ClaimCondition = ObservationCondition | AllCondition | AnyCondition | NotCondition;\n\nexport interface ClaimPredicate {\n\treadonly claimId: string;\n\treadonly statement: string;\n\treadonly requirement: RequirementLevel;\n\treadonly condition: ClaimCondition;\n}\n\nexport interface TaskSpec {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly taskId: string;\n\treadonly goal: string;\n\treadonly createdAt: string;\n\treadonly claims: readonly ClaimPredicate[];\n}\n\nexport type AttemptTrigger = \"initial\" | \"retry\" | \"failover\" | \"resume\";\n\nexport interface AttemptExecutor {\n\treadonly kind: string;\n\treadonly provider?: string;\n\treadonly model?: string;\n}\n\nexport type AttemptOutcome =\n\t| { readonly kind: \"completed\" }\n\t| { readonly kind: \"failed\"; readonly code: string; readonly message?: string }\n\t| { readonly kind: \"cancelled\"; readonly code: string };\n\n/** One completed execution. Retry and failover counts are derived from these records. */\nexport interface ExecutionAttempt {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly attemptId: string;\n\treadonly taskId: string;\n\treadonly sequence: number;\n\treadonly trigger: AttemptTrigger;\n\treadonly previousAttemptId?: string;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly executor: AttemptExecutor;\n\treadonly outcome: AttemptOutcome;\n}\n\n/** Immutable execution facts. Semantic pass/fail belongs only in ClaimEvaluation. */\nexport interface Observation {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly observationId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly observedAt: string;\n\treadonly kind: string;\n\treadonly source: {\n\t\treadonly kind: string;\n\t\treadonly id: string;\n\t};\n\treadonly facts: JsonObject;\n\treadonly evidenceRefs: readonly string[];\n}\n\nexport interface WaiverRecord {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly waiverId: string;\n\treadonly scope: {\n\t\treadonly taskId: string;\n\t\treadonly claimId: string;\n\t\treadonly attemptId?: string;\n\t};\n\treadonly approvedBy: string;\n\treadonly approvedAt: string;\n\treadonly expiresAt?: string;\n\treadonly rationale: string;\n\treadonly evidenceRefs: readonly string[];\n}\n\nexport type ClaimReasonCode = \"claim.satisfied\" | \"claim.violated\" | \"claim.observation_missing\";\n\nexport interface ClaimEvaluation {\n\treadonly claimId: string;\n\treadonly requirement: RequirementLevel;\n\treadonly result: ClaimResult;\n\treadonly reasonCode: ClaimReasonCode;\n\treadonly observationIds: readonly string[];\n\treadonly waiverId?: string;\n}\n\nexport interface EvaluationResult {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly evaluationId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly evaluatedAt: string;\n\treadonly claims: readonly ClaimEvaluation[];\n\treadonly semanticVerdict: SemanticVerdict;\n}\n\nexport interface EvaluationInput {\n\treadonly evaluationId: string;\n\treadonly evaluatedAt: string;\n\treadonly taskSpec: TaskSpec;\n\treadonly attempt: ExecutionAttempt;\n\treadonly observations: readonly Observation[];\n\treadonly waivers?: readonly WaiverRecord[];\n}\n\nexport interface RuntimeDecisionPolicy {\n\treadonly onFail: RuntimeAction;\n\treadonly onInconclusive: RuntimeAction;\n}\n\nexport type RuntimeDecisionReason = \"evaluation.pass\" | \"evaluation.fail\" | \"evaluation.inconclusive\";\n\nexport interface RuntimeDecision {\n\treadonly schemaVersion: ProtocolVersion;\n\treadonly decisionId: string;\n\treadonly taskId: string;\n\treadonly attemptId: string;\n\treadonly evaluationId: string;\n\treadonly decidedAt: string;\n\treadonly action: RuntimeAction;\n\treadonly reasonCode: RuntimeDecisionReason;\n}\n\nexport interface RuntimeDecisionInput {\n\treadonly decisionId: string;\n\treadonly decidedAt: string;\n\treadonly evaluation: EvaluationResult;\n\treadonly policy: RuntimeDecisionPolicy;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type EvaluationResult, type ExecutionAttempt, type Observation, type RuntimeDecision, type TaskSpec, type WaiverRecord } from "./types.ts";
|
|
2
|
+
export declare class ProtocolValidationError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function parseTaskSpec(value: unknown): TaskSpec;
|
|
6
|
+
export declare function parseExecutionAttempt(value: unknown): ExecutionAttempt;
|
|
7
|
+
export declare function parseObservation(value: unknown): Observation;
|
|
8
|
+
export declare function parseWaiverRecord(value: unknown): WaiverRecord;
|
|
9
|
+
export declare function parseEvaluationResult(value: unknown): EvaluationResult;
|
|
10
|
+
export declare function parseRuntimeDecision(value: unknown): RuntimeDecision;
|
|
11
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAGrB,KAAK,WAAW,EAEhB,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,MAAM,YAAY,CAAC;AAKpB,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AAkFD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAoBtD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CA6BtE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAc5D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAc9D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CA2BtE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAepE","sourcesContent":["import {\n\ttype ClaimCondition,\n\ttype EvaluationResult,\n\ttype ExecutionAttempt,\n\ttype JsonObject,\n\ttype JsonValue,\n\ttype Observation,\n\tPROTOCOL_VERSION,\n\ttype RuntimeDecision,\n\ttype TaskSpec,\n\ttype WaiverRecord,\n} from \"./types.ts\";\n\nconst ISO_TIMESTAMP = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\nconst MAX_CONDITION_DEPTH = 32;\n\nexport class ProtocolValidationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"ProtocolValidationError\";\n\t}\n}\n\nfunction record(value: unknown, path: string): Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\tthrow new ProtocolValidationError(`${path} must be an object`);\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nfunction string(value: unknown, path: string): string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new ProtocolValidationError(`${path} must be a non-empty string`);\n\t}\n\treturn value;\n}\n\nfunction timestamp(value: unknown, path: string): string {\n\tconst parsed = string(value, path);\n\tif (!ISO_TIMESTAMP.test(parsed) || Number.isNaN(Date.parse(parsed))) {\n\t\tthrow new ProtocolValidationError(`${path} must be an ISO 8601 UTC timestamp`);\n\t}\n\treturn parsed;\n}\n\nfunction version(value: Record<string, unknown>, path: string): void {\n\tif (value.schemaVersion !== PROTOCOL_VERSION) {\n\t\tthrow new ProtocolValidationError(`${path}.schemaVersion must be ${PROTOCOL_VERSION}`);\n\t}\n}\n\nfunction stringArray(value: unknown, path: string): readonly string[] {\n\tif (!Array.isArray(value)) throw new ProtocolValidationError(`${path} must be an array`);\n\treturn value.map((item, index) => string(item, `${path}[${index}]`));\n}\n\nfunction jsonValue(value: unknown, path: string, depth = 0): asserts value is JsonValue {\n\tif (depth > MAX_CONDITION_DEPTH) throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return;\n\tif (typeof value === \"number\" && Number.isFinite(value)) return;\n\tif (Array.isArray(value)) {\n\t\tvalue.forEach((item, index) => {\n\t\t\tjsonValue(item, `${path}[${index}]`, depth + 1);\n\t\t});\n\t\treturn;\n\t}\n\tconst object = record(value, path);\n\tfor (const [key, item] of Object.entries(object)) jsonValue(item, `${path}.${key}`, depth + 1);\n}\n\nfunction jsonObject(value: unknown, path: string): asserts value is JsonObject {\n\trecord(value, path);\n\tjsonValue(value, path);\n}\n\nfunction condition(value: unknown, path: string, depth = 0): asserts value is ClaimCondition {\n\tif (depth > MAX_CONDITION_DEPTH) throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);\n\tconst input = record(value, path);\n\tswitch (input.kind) {\n\t\tcase \"observation\":\n\t\t\tstring(input.observationKind, `${path}.observationKind`);\n\t\t\tif (input.scope !== \"attempt\" && input.scope !== \"task\") {\n\t\t\t\tthrow new ProtocolValidationError(`${path}.scope must be attempt or task`);\n\t\t\t}\n\t\t\tjsonObject(input.facts, `${path}.facts`);\n\t\t\treturn;\n\t\tcase \"all\":\n\t\tcase \"any\":\n\t\t\tif (!Array.isArray(input.conditions) || input.conditions.length === 0) {\n\t\t\t\tthrow new ProtocolValidationError(`${path}.conditions must be a non-empty array`);\n\t\t\t}\n\t\t\tinput.conditions.forEach((item, index) => {\n\t\t\t\tcondition(item, `${path}.conditions[${index}]`, depth + 1);\n\t\t\t});\n\t\t\treturn;\n\t\tcase \"not\":\n\t\t\tcondition(input.condition, `${path}.condition`, depth + 1);\n\t\t\treturn;\n\t\tdefault:\n\t\t\tthrow new ProtocolValidationError(`${path}.kind is unsupported`);\n\t}\n}\n\nexport function parseTaskSpec(value: unknown): TaskSpec {\n\tconst input = record(value, \"taskSpec\");\n\tversion(input, \"taskSpec\");\n\tstring(input.taskId, \"taskSpec.taskId\");\n\tstring(input.goal, \"taskSpec.goal\");\n\ttimestamp(input.createdAt, \"taskSpec.createdAt\");\n\tif (!Array.isArray(input.claims)) throw new ProtocolValidationError(\"taskSpec.claims must be an array\");\n\tconst claimIds = new Set<string>();\n\tfor (const [index, rawClaim] of input.claims.entries()) {\n\t\tconst claim = record(rawClaim, `taskSpec.claims[${index}]`);\n\t\tconst claimId = string(claim.claimId, `taskSpec.claims[${index}].claimId`);\n\t\tif (claimIds.has(claimId)) throw new ProtocolValidationError(`duplicate claimId ${claimId}`);\n\t\tclaimIds.add(claimId);\n\t\tstring(claim.statement, `taskSpec.claims[${index}].statement`);\n\t\tif (claim.requirement !== \"required\" && claim.requirement !== \"advisory\") {\n\t\t\tthrow new ProtocolValidationError(`taskSpec.claims[${index}].requirement is unsupported`);\n\t\t}\n\t\tcondition(claim.condition, `taskSpec.claims[${index}].condition`);\n\t}\n\treturn value as TaskSpec;\n}\n\nexport function parseExecutionAttempt(value: unknown): ExecutionAttempt {\n\tconst input = record(value, \"attempt\");\n\tversion(input, \"attempt\");\n\tstring(input.attemptId, \"attempt.attemptId\");\n\tstring(input.taskId, \"attempt.taskId\");\n\tif (!Number.isSafeInteger(input.sequence) || (input.sequence as number) < 1) {\n\t\tthrow new ProtocolValidationError(\"attempt.sequence must be a positive integer\");\n\t}\n\tif (![\"initial\", \"retry\", \"failover\", \"resume\"].includes(input.trigger as string)) {\n\t\tthrow new ProtocolValidationError(\"attempt.trigger is unsupported\");\n\t}\n\tif (input.previousAttemptId !== undefined) string(input.previousAttemptId, \"attempt.previousAttemptId\");\n\tconst startedAt = timestamp(input.startedAt, \"attempt.startedAt\");\n\tconst finishedAt = timestamp(input.finishedAt, \"attempt.finishedAt\");\n\tif (finishedAt < startedAt) throw new ProtocolValidationError(\"attempt.finishedAt precedes startedAt\");\n\tconst executor = record(input.executor, \"attempt.executor\");\n\tstring(executor.kind, \"attempt.executor.kind\");\n\tif (executor.provider !== undefined) string(executor.provider, \"attempt.executor.provider\");\n\tif (executor.model !== undefined) string(executor.model, \"attempt.executor.model\");\n\tconst outcome = record(input.outcome, \"attempt.outcome\");\n\tif (outcome.kind === \"failed\") {\n\t\tstring(outcome.code, \"attempt.outcome.code\");\n\t\tif (outcome.message !== undefined) string(outcome.message, \"attempt.outcome.message\");\n\t} else if (outcome.kind === \"cancelled\") {\n\t\tstring(outcome.code, \"attempt.outcome.code\");\n\t} else if (outcome.kind !== \"completed\") {\n\t\tthrow new ProtocolValidationError(\"attempt.outcome.kind is unsupported\");\n\t}\n\treturn value as ExecutionAttempt;\n}\n\nexport function parseObservation(value: unknown): Observation {\n\tconst input = record(value, \"observation\");\n\tversion(input, \"observation\");\n\tstring(input.observationId, \"observation.observationId\");\n\tstring(input.taskId, \"observation.taskId\");\n\tstring(input.attemptId, \"observation.attemptId\");\n\ttimestamp(input.observedAt, \"observation.observedAt\");\n\tstring(input.kind, \"observation.kind\");\n\tconst source = record(input.source, \"observation.source\");\n\tstring(source.kind, \"observation.source.kind\");\n\tstring(source.id, \"observation.source.id\");\n\tjsonObject(input.facts, \"observation.facts\");\n\tstringArray(input.evidenceRefs, \"observation.evidenceRefs\");\n\treturn value as Observation;\n}\n\nexport function parseWaiverRecord(value: unknown): WaiverRecord {\n\tconst input = record(value, \"waiver\");\n\tversion(input, \"waiver\");\n\tstring(input.waiverId, \"waiver.waiverId\");\n\tconst scope = record(input.scope, \"waiver.scope\");\n\tstring(scope.taskId, \"waiver.scope.taskId\");\n\tstring(scope.claimId, \"waiver.scope.claimId\");\n\tif (scope.attemptId !== undefined) string(scope.attemptId, \"waiver.scope.attemptId\");\n\tstring(input.approvedBy, \"waiver.approvedBy\");\n\ttimestamp(input.approvedAt, \"waiver.approvedAt\");\n\tif (input.expiresAt !== undefined) timestamp(input.expiresAt, \"waiver.expiresAt\");\n\tstring(input.rationale, \"waiver.rationale\");\n\tstringArray(input.evidenceRefs, \"waiver.evidenceRefs\");\n\treturn value as WaiverRecord;\n}\n\nexport function parseEvaluationResult(value: unknown): EvaluationResult {\n\tconst input = record(value, \"evaluation\");\n\tversion(input, \"evaluation\");\n\tstring(input.evaluationId, \"evaluation.evaluationId\");\n\tstring(input.taskId, \"evaluation.taskId\");\n\tstring(input.attemptId, \"evaluation.attemptId\");\n\ttimestamp(input.evaluatedAt, \"evaluation.evaluatedAt\");\n\tif (!Array.isArray(input.claims)) throw new ProtocolValidationError(\"evaluation.claims must be an array\");\n\tfor (const [index, rawClaim] of input.claims.entries()) {\n\t\tconst claim = record(rawClaim, `evaluation.claims[${index}]`);\n\t\tstring(claim.claimId, `evaluation.claims[${index}].claimId`);\n\t\tif (claim.requirement !== \"required\" && claim.requirement !== \"advisory\") {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].requirement is unsupported`);\n\t\t}\n\t\tif (![\"satisfied\", \"violated\", \"inconclusive\"].includes(claim.result as string)) {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].result is unsupported`);\n\t\t}\n\t\tif (![\"claim.satisfied\", \"claim.violated\", \"claim.observation_missing\"].includes(claim.reasonCode as string)) {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].reasonCode is unsupported`);\n\t\t}\n\t\tstringArray(claim.observationIds, `evaluation.claims[${index}].observationIds`);\n\t\tif (claim.waiverId !== undefined) string(claim.waiverId, `evaluation.claims[${index}].waiverId`);\n\t}\n\tif (![\"pass\", \"fail\", \"inconclusive\"].includes(input.semanticVerdict as string)) {\n\t\tthrow new ProtocolValidationError(\"evaluation.semanticVerdict is unsupported\");\n\t}\n\treturn value as EvaluationResult;\n}\n\nexport function parseRuntimeDecision(value: unknown): RuntimeDecision {\n\tconst input = record(value, \"decision\");\n\tversion(input, \"decision\");\n\tstring(input.decisionId, \"decision.decisionId\");\n\tstring(input.taskId, \"decision.taskId\");\n\tstring(input.attemptId, \"decision.attemptId\");\n\tstring(input.evaluationId, \"decision.evaluationId\");\n\ttimestamp(input.decidedAt, \"decision.decidedAt\");\n\tif (![\"continue\", \"retry\", \"failover\", \"stop\"].includes(input.action as string)) {\n\t\tthrow new ProtocolValidationError(\"decision.action is unsupported\");\n\t}\n\tif (![\"evaluation.pass\", \"evaluation.fail\", \"evaluation.inconclusive\"].includes(input.reasonCode as string)) {\n\t\tthrow new ProtocolValidationError(\"decision.reasonCode is unsupported\");\n\t}\n\treturn value as RuntimeDecision;\n}\n"]}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { PROTOCOL_VERSION, } from "./types.js";
|
|
2
|
+
const ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
3
|
+
const MAX_CONDITION_DEPTH = 32;
|
|
4
|
+
export class ProtocolValidationError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "ProtocolValidationError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function record(value, path) {
|
|
11
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
12
|
+
throw new ProtocolValidationError(`${path} must be an object`);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function string(value, path) {
|
|
17
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
18
|
+
throw new ProtocolValidationError(`${path} must be a non-empty string`);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function timestamp(value, path) {
|
|
23
|
+
const parsed = string(value, path);
|
|
24
|
+
if (!ISO_TIMESTAMP.test(parsed) || Number.isNaN(Date.parse(parsed))) {
|
|
25
|
+
throw new ProtocolValidationError(`${path} must be an ISO 8601 UTC timestamp`);
|
|
26
|
+
}
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
function version(value, path) {
|
|
30
|
+
if (value.schemaVersion !== PROTOCOL_VERSION) {
|
|
31
|
+
throw new ProtocolValidationError(`${path}.schemaVersion must be ${PROTOCOL_VERSION}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function stringArray(value, path) {
|
|
35
|
+
if (!Array.isArray(value))
|
|
36
|
+
throw new ProtocolValidationError(`${path} must be an array`);
|
|
37
|
+
return value.map((item, index) => string(item, `${path}[${index}]`));
|
|
38
|
+
}
|
|
39
|
+
function jsonValue(value, path, depth = 0) {
|
|
40
|
+
if (depth > MAX_CONDITION_DEPTH)
|
|
41
|
+
throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);
|
|
42
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
43
|
+
return;
|
|
44
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
45
|
+
return;
|
|
46
|
+
if (Array.isArray(value)) {
|
|
47
|
+
value.forEach((item, index) => {
|
|
48
|
+
jsonValue(item, `${path}[${index}]`, depth + 1);
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const object = record(value, path);
|
|
53
|
+
for (const [key, item] of Object.entries(object))
|
|
54
|
+
jsonValue(item, `${path}.${key}`, depth + 1);
|
|
55
|
+
}
|
|
56
|
+
function jsonObject(value, path) {
|
|
57
|
+
record(value, path);
|
|
58
|
+
jsonValue(value, path);
|
|
59
|
+
}
|
|
60
|
+
function condition(value, path, depth = 0) {
|
|
61
|
+
if (depth > MAX_CONDITION_DEPTH)
|
|
62
|
+
throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);
|
|
63
|
+
const input = record(value, path);
|
|
64
|
+
switch (input.kind) {
|
|
65
|
+
case "observation":
|
|
66
|
+
string(input.observationKind, `${path}.observationKind`);
|
|
67
|
+
if (input.scope !== "attempt" && input.scope !== "task") {
|
|
68
|
+
throw new ProtocolValidationError(`${path}.scope must be attempt or task`);
|
|
69
|
+
}
|
|
70
|
+
jsonObject(input.facts, `${path}.facts`);
|
|
71
|
+
return;
|
|
72
|
+
case "all":
|
|
73
|
+
case "any":
|
|
74
|
+
if (!Array.isArray(input.conditions) || input.conditions.length === 0) {
|
|
75
|
+
throw new ProtocolValidationError(`${path}.conditions must be a non-empty array`);
|
|
76
|
+
}
|
|
77
|
+
input.conditions.forEach((item, index) => {
|
|
78
|
+
condition(item, `${path}.conditions[${index}]`, depth + 1);
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
case "not":
|
|
82
|
+
condition(input.condition, `${path}.condition`, depth + 1);
|
|
83
|
+
return;
|
|
84
|
+
default:
|
|
85
|
+
throw new ProtocolValidationError(`${path}.kind is unsupported`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function parseTaskSpec(value) {
|
|
89
|
+
const input = record(value, "taskSpec");
|
|
90
|
+
version(input, "taskSpec");
|
|
91
|
+
string(input.taskId, "taskSpec.taskId");
|
|
92
|
+
string(input.goal, "taskSpec.goal");
|
|
93
|
+
timestamp(input.createdAt, "taskSpec.createdAt");
|
|
94
|
+
if (!Array.isArray(input.claims))
|
|
95
|
+
throw new ProtocolValidationError("taskSpec.claims must be an array");
|
|
96
|
+
const claimIds = new Set();
|
|
97
|
+
for (const [index, rawClaim] of input.claims.entries()) {
|
|
98
|
+
const claim = record(rawClaim, `taskSpec.claims[${index}]`);
|
|
99
|
+
const claimId = string(claim.claimId, `taskSpec.claims[${index}].claimId`);
|
|
100
|
+
if (claimIds.has(claimId))
|
|
101
|
+
throw new ProtocolValidationError(`duplicate claimId ${claimId}`);
|
|
102
|
+
claimIds.add(claimId);
|
|
103
|
+
string(claim.statement, `taskSpec.claims[${index}].statement`);
|
|
104
|
+
if (claim.requirement !== "required" && claim.requirement !== "advisory") {
|
|
105
|
+
throw new ProtocolValidationError(`taskSpec.claims[${index}].requirement is unsupported`);
|
|
106
|
+
}
|
|
107
|
+
condition(claim.condition, `taskSpec.claims[${index}].condition`);
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
export function parseExecutionAttempt(value) {
|
|
112
|
+
const input = record(value, "attempt");
|
|
113
|
+
version(input, "attempt");
|
|
114
|
+
string(input.attemptId, "attempt.attemptId");
|
|
115
|
+
string(input.taskId, "attempt.taskId");
|
|
116
|
+
if (!Number.isSafeInteger(input.sequence) || input.sequence < 1) {
|
|
117
|
+
throw new ProtocolValidationError("attempt.sequence must be a positive integer");
|
|
118
|
+
}
|
|
119
|
+
if (!["initial", "retry", "failover", "resume"].includes(input.trigger)) {
|
|
120
|
+
throw new ProtocolValidationError("attempt.trigger is unsupported");
|
|
121
|
+
}
|
|
122
|
+
if (input.previousAttemptId !== undefined)
|
|
123
|
+
string(input.previousAttemptId, "attempt.previousAttemptId");
|
|
124
|
+
const startedAt = timestamp(input.startedAt, "attempt.startedAt");
|
|
125
|
+
const finishedAt = timestamp(input.finishedAt, "attempt.finishedAt");
|
|
126
|
+
if (finishedAt < startedAt)
|
|
127
|
+
throw new ProtocolValidationError("attempt.finishedAt precedes startedAt");
|
|
128
|
+
const executor = record(input.executor, "attempt.executor");
|
|
129
|
+
string(executor.kind, "attempt.executor.kind");
|
|
130
|
+
if (executor.provider !== undefined)
|
|
131
|
+
string(executor.provider, "attempt.executor.provider");
|
|
132
|
+
if (executor.model !== undefined)
|
|
133
|
+
string(executor.model, "attempt.executor.model");
|
|
134
|
+
const outcome = record(input.outcome, "attempt.outcome");
|
|
135
|
+
if (outcome.kind === "failed") {
|
|
136
|
+
string(outcome.code, "attempt.outcome.code");
|
|
137
|
+
if (outcome.message !== undefined)
|
|
138
|
+
string(outcome.message, "attempt.outcome.message");
|
|
139
|
+
}
|
|
140
|
+
else if (outcome.kind === "cancelled") {
|
|
141
|
+
string(outcome.code, "attempt.outcome.code");
|
|
142
|
+
}
|
|
143
|
+
else if (outcome.kind !== "completed") {
|
|
144
|
+
throw new ProtocolValidationError("attempt.outcome.kind is unsupported");
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
export function parseObservation(value) {
|
|
149
|
+
const input = record(value, "observation");
|
|
150
|
+
version(input, "observation");
|
|
151
|
+
string(input.observationId, "observation.observationId");
|
|
152
|
+
string(input.taskId, "observation.taskId");
|
|
153
|
+
string(input.attemptId, "observation.attemptId");
|
|
154
|
+
timestamp(input.observedAt, "observation.observedAt");
|
|
155
|
+
string(input.kind, "observation.kind");
|
|
156
|
+
const source = record(input.source, "observation.source");
|
|
157
|
+
string(source.kind, "observation.source.kind");
|
|
158
|
+
string(source.id, "observation.source.id");
|
|
159
|
+
jsonObject(input.facts, "observation.facts");
|
|
160
|
+
stringArray(input.evidenceRefs, "observation.evidenceRefs");
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
export function parseWaiverRecord(value) {
|
|
164
|
+
const input = record(value, "waiver");
|
|
165
|
+
version(input, "waiver");
|
|
166
|
+
string(input.waiverId, "waiver.waiverId");
|
|
167
|
+
const scope = record(input.scope, "waiver.scope");
|
|
168
|
+
string(scope.taskId, "waiver.scope.taskId");
|
|
169
|
+
string(scope.claimId, "waiver.scope.claimId");
|
|
170
|
+
if (scope.attemptId !== undefined)
|
|
171
|
+
string(scope.attemptId, "waiver.scope.attemptId");
|
|
172
|
+
string(input.approvedBy, "waiver.approvedBy");
|
|
173
|
+
timestamp(input.approvedAt, "waiver.approvedAt");
|
|
174
|
+
if (input.expiresAt !== undefined)
|
|
175
|
+
timestamp(input.expiresAt, "waiver.expiresAt");
|
|
176
|
+
string(input.rationale, "waiver.rationale");
|
|
177
|
+
stringArray(input.evidenceRefs, "waiver.evidenceRefs");
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
export function parseEvaluationResult(value) {
|
|
181
|
+
const input = record(value, "evaluation");
|
|
182
|
+
version(input, "evaluation");
|
|
183
|
+
string(input.evaluationId, "evaluation.evaluationId");
|
|
184
|
+
string(input.taskId, "evaluation.taskId");
|
|
185
|
+
string(input.attemptId, "evaluation.attemptId");
|
|
186
|
+
timestamp(input.evaluatedAt, "evaluation.evaluatedAt");
|
|
187
|
+
if (!Array.isArray(input.claims))
|
|
188
|
+
throw new ProtocolValidationError("evaluation.claims must be an array");
|
|
189
|
+
for (const [index, rawClaim] of input.claims.entries()) {
|
|
190
|
+
const claim = record(rawClaim, `evaluation.claims[${index}]`);
|
|
191
|
+
string(claim.claimId, `evaluation.claims[${index}].claimId`);
|
|
192
|
+
if (claim.requirement !== "required" && claim.requirement !== "advisory") {
|
|
193
|
+
throw new ProtocolValidationError(`evaluation.claims[${index}].requirement is unsupported`);
|
|
194
|
+
}
|
|
195
|
+
if (!["satisfied", "violated", "inconclusive"].includes(claim.result)) {
|
|
196
|
+
throw new ProtocolValidationError(`evaluation.claims[${index}].result is unsupported`);
|
|
197
|
+
}
|
|
198
|
+
if (!["claim.satisfied", "claim.violated", "claim.observation_missing"].includes(claim.reasonCode)) {
|
|
199
|
+
throw new ProtocolValidationError(`evaluation.claims[${index}].reasonCode is unsupported`);
|
|
200
|
+
}
|
|
201
|
+
stringArray(claim.observationIds, `evaluation.claims[${index}].observationIds`);
|
|
202
|
+
if (claim.waiverId !== undefined)
|
|
203
|
+
string(claim.waiverId, `evaluation.claims[${index}].waiverId`);
|
|
204
|
+
}
|
|
205
|
+
if (!["pass", "fail", "inconclusive"].includes(input.semanticVerdict)) {
|
|
206
|
+
throw new ProtocolValidationError("evaluation.semanticVerdict is unsupported");
|
|
207
|
+
}
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
export function parseRuntimeDecision(value) {
|
|
211
|
+
const input = record(value, "decision");
|
|
212
|
+
version(input, "decision");
|
|
213
|
+
string(input.decisionId, "decision.decisionId");
|
|
214
|
+
string(input.taskId, "decision.taskId");
|
|
215
|
+
string(input.attemptId, "decision.attemptId");
|
|
216
|
+
string(input.evaluationId, "decision.evaluationId");
|
|
217
|
+
timestamp(input.decidedAt, "decision.decidedAt");
|
|
218
|
+
if (!["continue", "retry", "failover", "stop"].includes(input.action)) {
|
|
219
|
+
throw new ProtocolValidationError("decision.action is unsupported");
|
|
220
|
+
}
|
|
221
|
+
if (!["evaluation.pass", "evaluation.fail", "evaluation.inconclusive"].includes(input.reasonCode)) {
|
|
222
|
+
throw new ProtocolValidationError("decision.reasonCode is unsupported");
|
|
223
|
+
}
|
|
224
|
+
return value;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ClaimCondition,\n\ttype EvaluationResult,\n\ttype ExecutionAttempt,\n\ttype JsonObject,\n\ttype JsonValue,\n\ttype Observation,\n\tPROTOCOL_VERSION,\n\ttype RuntimeDecision,\n\ttype TaskSpec,\n\ttype WaiverRecord,\n} from \"./types.ts\";\n\nconst ISO_TIMESTAMP = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\nconst MAX_CONDITION_DEPTH = 32;\n\nexport class ProtocolValidationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"ProtocolValidationError\";\n\t}\n}\n\nfunction record(value: unknown, path: string): Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\tthrow new ProtocolValidationError(`${path} must be an object`);\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nfunction string(value: unknown, path: string): string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new ProtocolValidationError(`${path} must be a non-empty string`);\n\t}\n\treturn value;\n}\n\nfunction timestamp(value: unknown, path: string): string {\n\tconst parsed = string(value, path);\n\tif (!ISO_TIMESTAMP.test(parsed) || Number.isNaN(Date.parse(parsed))) {\n\t\tthrow new ProtocolValidationError(`${path} must be an ISO 8601 UTC timestamp`);\n\t}\n\treturn parsed;\n}\n\nfunction version(value: Record<string, unknown>, path: string): void {\n\tif (value.schemaVersion !== PROTOCOL_VERSION) {\n\t\tthrow new ProtocolValidationError(`${path}.schemaVersion must be ${PROTOCOL_VERSION}`);\n\t}\n}\n\nfunction stringArray(value: unknown, path: string): readonly string[] {\n\tif (!Array.isArray(value)) throw new ProtocolValidationError(`${path} must be an array`);\n\treturn value.map((item, index) => string(item, `${path}[${index}]`));\n}\n\nfunction jsonValue(value: unknown, path: string, depth = 0): asserts value is JsonValue {\n\tif (depth > MAX_CONDITION_DEPTH) throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return;\n\tif (typeof value === \"number\" && Number.isFinite(value)) return;\n\tif (Array.isArray(value)) {\n\t\tvalue.forEach((item, index) => {\n\t\t\tjsonValue(item, `${path}[${index}]`, depth + 1);\n\t\t});\n\t\treturn;\n\t}\n\tconst object = record(value, path);\n\tfor (const [key, item] of Object.entries(object)) jsonValue(item, `${path}.${key}`, depth + 1);\n}\n\nfunction jsonObject(value: unknown, path: string): asserts value is JsonObject {\n\trecord(value, path);\n\tjsonValue(value, path);\n}\n\nfunction condition(value: unknown, path: string, depth = 0): asserts value is ClaimCondition {\n\tif (depth > MAX_CONDITION_DEPTH) throw new ProtocolValidationError(`${path} exceeds maximum nesting depth`);\n\tconst input = record(value, path);\n\tswitch (input.kind) {\n\t\tcase \"observation\":\n\t\t\tstring(input.observationKind, `${path}.observationKind`);\n\t\t\tif (input.scope !== \"attempt\" && input.scope !== \"task\") {\n\t\t\t\tthrow new ProtocolValidationError(`${path}.scope must be attempt or task`);\n\t\t\t}\n\t\t\tjsonObject(input.facts, `${path}.facts`);\n\t\t\treturn;\n\t\tcase \"all\":\n\t\tcase \"any\":\n\t\t\tif (!Array.isArray(input.conditions) || input.conditions.length === 0) {\n\t\t\t\tthrow new ProtocolValidationError(`${path}.conditions must be a non-empty array`);\n\t\t\t}\n\t\t\tinput.conditions.forEach((item, index) => {\n\t\t\t\tcondition(item, `${path}.conditions[${index}]`, depth + 1);\n\t\t\t});\n\t\t\treturn;\n\t\tcase \"not\":\n\t\t\tcondition(input.condition, `${path}.condition`, depth + 1);\n\t\t\treturn;\n\t\tdefault:\n\t\t\tthrow new ProtocolValidationError(`${path}.kind is unsupported`);\n\t}\n}\n\nexport function parseTaskSpec(value: unknown): TaskSpec {\n\tconst input = record(value, \"taskSpec\");\n\tversion(input, \"taskSpec\");\n\tstring(input.taskId, \"taskSpec.taskId\");\n\tstring(input.goal, \"taskSpec.goal\");\n\ttimestamp(input.createdAt, \"taskSpec.createdAt\");\n\tif (!Array.isArray(input.claims)) throw new ProtocolValidationError(\"taskSpec.claims must be an array\");\n\tconst claimIds = new Set<string>();\n\tfor (const [index, rawClaim] of input.claims.entries()) {\n\t\tconst claim = record(rawClaim, `taskSpec.claims[${index}]`);\n\t\tconst claimId = string(claim.claimId, `taskSpec.claims[${index}].claimId`);\n\t\tif (claimIds.has(claimId)) throw new ProtocolValidationError(`duplicate claimId ${claimId}`);\n\t\tclaimIds.add(claimId);\n\t\tstring(claim.statement, `taskSpec.claims[${index}].statement`);\n\t\tif (claim.requirement !== \"required\" && claim.requirement !== \"advisory\") {\n\t\t\tthrow new ProtocolValidationError(`taskSpec.claims[${index}].requirement is unsupported`);\n\t\t}\n\t\tcondition(claim.condition, `taskSpec.claims[${index}].condition`);\n\t}\n\treturn value as TaskSpec;\n}\n\nexport function parseExecutionAttempt(value: unknown): ExecutionAttempt {\n\tconst input = record(value, \"attempt\");\n\tversion(input, \"attempt\");\n\tstring(input.attemptId, \"attempt.attemptId\");\n\tstring(input.taskId, \"attempt.taskId\");\n\tif (!Number.isSafeInteger(input.sequence) || (input.sequence as number) < 1) {\n\t\tthrow new ProtocolValidationError(\"attempt.sequence must be a positive integer\");\n\t}\n\tif (![\"initial\", \"retry\", \"failover\", \"resume\"].includes(input.trigger as string)) {\n\t\tthrow new ProtocolValidationError(\"attempt.trigger is unsupported\");\n\t}\n\tif (input.previousAttemptId !== undefined) string(input.previousAttemptId, \"attempt.previousAttemptId\");\n\tconst startedAt = timestamp(input.startedAt, \"attempt.startedAt\");\n\tconst finishedAt = timestamp(input.finishedAt, \"attempt.finishedAt\");\n\tif (finishedAt < startedAt) throw new ProtocolValidationError(\"attempt.finishedAt precedes startedAt\");\n\tconst executor = record(input.executor, \"attempt.executor\");\n\tstring(executor.kind, \"attempt.executor.kind\");\n\tif (executor.provider !== undefined) string(executor.provider, \"attempt.executor.provider\");\n\tif (executor.model !== undefined) string(executor.model, \"attempt.executor.model\");\n\tconst outcome = record(input.outcome, \"attempt.outcome\");\n\tif (outcome.kind === \"failed\") {\n\t\tstring(outcome.code, \"attempt.outcome.code\");\n\t\tif (outcome.message !== undefined) string(outcome.message, \"attempt.outcome.message\");\n\t} else if (outcome.kind === \"cancelled\") {\n\t\tstring(outcome.code, \"attempt.outcome.code\");\n\t} else if (outcome.kind !== \"completed\") {\n\t\tthrow new ProtocolValidationError(\"attempt.outcome.kind is unsupported\");\n\t}\n\treturn value as ExecutionAttempt;\n}\n\nexport function parseObservation(value: unknown): Observation {\n\tconst input = record(value, \"observation\");\n\tversion(input, \"observation\");\n\tstring(input.observationId, \"observation.observationId\");\n\tstring(input.taskId, \"observation.taskId\");\n\tstring(input.attemptId, \"observation.attemptId\");\n\ttimestamp(input.observedAt, \"observation.observedAt\");\n\tstring(input.kind, \"observation.kind\");\n\tconst source = record(input.source, \"observation.source\");\n\tstring(source.kind, \"observation.source.kind\");\n\tstring(source.id, \"observation.source.id\");\n\tjsonObject(input.facts, \"observation.facts\");\n\tstringArray(input.evidenceRefs, \"observation.evidenceRefs\");\n\treturn value as Observation;\n}\n\nexport function parseWaiverRecord(value: unknown): WaiverRecord {\n\tconst input = record(value, \"waiver\");\n\tversion(input, \"waiver\");\n\tstring(input.waiverId, \"waiver.waiverId\");\n\tconst scope = record(input.scope, \"waiver.scope\");\n\tstring(scope.taskId, \"waiver.scope.taskId\");\n\tstring(scope.claimId, \"waiver.scope.claimId\");\n\tif (scope.attemptId !== undefined) string(scope.attemptId, \"waiver.scope.attemptId\");\n\tstring(input.approvedBy, \"waiver.approvedBy\");\n\ttimestamp(input.approvedAt, \"waiver.approvedAt\");\n\tif (input.expiresAt !== undefined) timestamp(input.expiresAt, \"waiver.expiresAt\");\n\tstring(input.rationale, \"waiver.rationale\");\n\tstringArray(input.evidenceRefs, \"waiver.evidenceRefs\");\n\treturn value as WaiverRecord;\n}\n\nexport function parseEvaluationResult(value: unknown): EvaluationResult {\n\tconst input = record(value, \"evaluation\");\n\tversion(input, \"evaluation\");\n\tstring(input.evaluationId, \"evaluation.evaluationId\");\n\tstring(input.taskId, \"evaluation.taskId\");\n\tstring(input.attemptId, \"evaluation.attemptId\");\n\ttimestamp(input.evaluatedAt, \"evaluation.evaluatedAt\");\n\tif (!Array.isArray(input.claims)) throw new ProtocolValidationError(\"evaluation.claims must be an array\");\n\tfor (const [index, rawClaim] of input.claims.entries()) {\n\t\tconst claim = record(rawClaim, `evaluation.claims[${index}]`);\n\t\tstring(claim.claimId, `evaluation.claims[${index}].claimId`);\n\t\tif (claim.requirement !== \"required\" && claim.requirement !== \"advisory\") {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].requirement is unsupported`);\n\t\t}\n\t\tif (![\"satisfied\", \"violated\", \"inconclusive\"].includes(claim.result as string)) {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].result is unsupported`);\n\t\t}\n\t\tif (![\"claim.satisfied\", \"claim.violated\", \"claim.observation_missing\"].includes(claim.reasonCode as string)) {\n\t\t\tthrow new ProtocolValidationError(`evaluation.claims[${index}].reasonCode is unsupported`);\n\t\t}\n\t\tstringArray(claim.observationIds, `evaluation.claims[${index}].observationIds`);\n\t\tif (claim.waiverId !== undefined) string(claim.waiverId, `evaluation.claims[${index}].waiverId`);\n\t}\n\tif (![\"pass\", \"fail\", \"inconclusive\"].includes(input.semanticVerdict as string)) {\n\t\tthrow new ProtocolValidationError(\"evaluation.semanticVerdict is unsupported\");\n\t}\n\treturn value as EvaluationResult;\n}\n\nexport function parseRuntimeDecision(value: unknown): RuntimeDecision {\n\tconst input = record(value, \"decision\");\n\tversion(input, \"decision\");\n\tstring(input.decisionId, \"decision.decisionId\");\n\tstring(input.taskId, \"decision.taskId\");\n\tstring(input.attemptId, \"decision.attemptId\");\n\tstring(input.evaluationId, \"decision.evaluationId\");\n\ttimestamp(input.decidedAt, \"decision.decidedAt\");\n\tif (![\"continue\", \"retry\", \"failover\", \"stop\"].includes(input.action as string)) {\n\t\tthrow new ProtocolValidationError(\"decision.action is unsupported\");\n\t}\n\tif (![\"evaluation.pass\", \"evaluation.fail\", \"evaluation.inconclusive\"].includes(input.reasonCode as string)) {\n\t\tthrow new ProtocolValidationError(\"decision.reasonCode is unsupported\");\n\t}\n\treturn value as RuntimeDecision;\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "omk-protocol",
|
|
3
|
+
"version": "0.96.0",
|
|
4
|
+
"description": "Canonical OMK Run Protocol contracts and pure semantic reducers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"clean": "shx rm -rf dist",
|
|
21
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
22
|
+
"test": "vitest --run",
|
|
23
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"omk",
|
|
27
|
+
"protocol",
|
|
28
|
+
"orchestration"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/dmae97/omk.git",
|
|
34
|
+
"directory": "packages/protocol"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=22.19.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "24.12.4",
|
|
41
|
+
"shx": "0.4.0",
|
|
42
|
+
"typescript": "5.9.3",
|
|
43
|
+
"vitest": "3.2.6"
|
|
44
|
+
}
|
|
45
|
+
}
|