project-tiny-context-harness 0.7.3 → 0.7.5
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/LICENSE +21 -21
- package/README.md +355 -343
- package/assets/README.md +539 -494
- package/assets/README.zh-CN.md +300 -273
- package/assets/agents/.gitkeep +1 -1
- package/assets/agents/AGENTS_CORE.md +55 -53
- package/assets/context_templates/architecture.md +33 -33
- package/assets/context_templates/area.md +39 -39
- package/assets/context_templates/context.toml +30 -30
- package/assets/context_templates/deployment.md +35 -35
- package/assets/context_templates/global.md +51 -51
- package/assets/context_templates/product-surface-contract.md +64 -57
- package/assets/context_templates/screen-contract.md +180 -0
- package/assets/context_templates/verification.md +32 -32
- package/assets/github/.gitkeep +1 -1
- package/assets/github/harness.yml +41 -41
- package/assets/make/.gitkeep +1 -1
- package/assets/make/ty-context.mk +48 -48
- package/assets/skills/context_development_engineer/SKILL.md +92 -90
- package/assets/skills/context_full_project_export/SKILL.md +70 -70
- package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
- package/assets/skills/context_product_plan/SKILL.md +77 -76
- package/assets/skills/context_surface_contract/SKILL.md +177 -162
- package/assets/skills/context_uiux_design/SKILL.md +108 -91
- package/assets/skills/long-task-workflow/SKILL.md +83 -83
- package/assets/skills/long-task-workflow/agents/openai.yaml +4 -4
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +57 -53
- package/assets/skills/long-task-workflow/references/contract-authoring.md +95 -77
- package/assets/skills/long-task-workflow/references/evidence-design.md +71 -58
- package/assets/skills/normal-long-task/SKILL.md +12 -12
- package/assets/skills/source-plan-authoring/SKILL.md +293 -290
- package/dist/commands/long-task-authoring.js +25 -0
- package/dist/commands/long-task.js +3 -0
- package/dist/lib/design-md.d.ts +7 -0
- package/dist/lib/design-md.js +47 -6
- package/dist/lib/doctor.js +19 -4
- package/dist/lib/long-task-activation-validation.js +13 -2
- package/dist/lib/long-task-authoring-authority-preview.js +1 -0
- package/dist/lib/long-task-authority-material-diff.js +54 -0
- package/dist/lib/long-task-authority-materials.d.ts +2 -2
- package/dist/lib/long-task-authority-materials.js +20 -0
- package/dist/lib/long-task-authority-policy.d.ts +26 -0
- package/dist/lib/long-task-authority-policy.js +23 -0
- package/dist/lib/long-task-authority-revision-analysis.d.ts +33 -0
- package/dist/lib/long-task-authority-revision-analysis.js +91 -0
- package/dist/lib/long-task-authority-revision.js +93 -158
- package/dist/lib/long-task-authority-types.d.ts +21 -0
- package/dist/lib/long-task-authority.js +32 -3
- package/dist/lib/long-task-check-evidence-decoder.d.ts +2 -2
- package/dist/lib/long-task-check-evidence-decoder.js +11 -1
- package/dist/lib/long-task-check-execution-policy.d.ts +3 -0
- package/dist/lib/long-task-check-execution-policy.js +5 -0
- package/dist/lib/long-task-check-runner.js +2 -0
- package/dist/lib/long-task-check-shape.js +33 -3
- package/dist/lib/long-task-claim-definitions.js +14 -0
- package/dist/lib/long-task-conformance-policy.d.ts +5 -0
- package/dist/lib/long-task-conformance-policy.js +35 -0
- package/dist/lib/long-task-contract-types.d.ts +28 -4
- package/dist/lib/long-task-delivery-compiler.js +1 -0
- package/dist/lib/long-task-delivery-parser.js +5 -2
- package/dist/lib/long-task-delivery-types.d.ts +2 -0
- package/dist/lib/long-task-delivery-types.js +2 -0
- package/dist/lib/long-task-delivery-validation.js +11 -0
- package/dist/lib/long-task-evidence-capability-codec.d.ts +2 -0
- package/dist/lib/long-task-evidence-capability-codec.js +231 -0
- package/dist/lib/long-task-evidence-capability-policy.d.ts +8 -0
- package/dist/lib/long-task-evidence-capability-policy.js +147 -0
- package/dist/lib/long-task-evidence-capability-runtime.d.ts +2 -0
- package/dist/lib/long-task-evidence-capability-runtime.js +86 -0
- package/dist/lib/long-task-evidence-capability-types.d.ts +74 -0
- package/dist/lib/long-task-evidence-capability-types.js +1 -0
- package/dist/lib/long-task-evidence-findings.js +5 -1
- package/dist/lib/long-task-evidence-v2.js +38 -23
- package/dist/lib/long-task-final-v2.js +42 -1
- package/dist/lib/long-task-outcome-parser.js +14 -3
- package/dist/lib/long-task-playwright-evidence.d.ts +2 -1
- package/dist/lib/long-task-playwright-evidence.js +70 -2
- package/dist/lib/long-task-product-shape.js +28 -0
- package/dist/lib/long-task-progress.js +4 -0
- package/dist/lib/long-task-root-shape.d.ts +1 -0
- package/dist/lib/long-task-root-shape.js +84 -3
- package/dist/lib/long-task-runner-environment.js +1 -1
- package/dist/lib/long-task-runner-freeze.d.ts +2 -2
- package/dist/lib/long-task-runner-freeze.js +3 -1
- package/dist/lib/long-task-runtime-types.d.ts +13 -0
- package/dist/lib/long-task-semantic-contract-types.d.ts +36 -0
- package/dist/lib/long-task-semantic-contract-types.js +1 -0
- package/dist/lib/long-task-semantic-drift-migration.d.ts +3 -0
- package/dist/lib/long-task-semantic-drift-migration.js +68 -0
- package/dist/lib/long-task-shape-primitives.d.ts +3 -0
- package/dist/lib/long-task-shape-primitives.js +25 -0
- package/dist/lib/long-task-source-target-index.js +14 -0
- package/dist/lib/long-task-stage-policy.d.ts +4 -0
- package/dist/lib/long-task-stage-policy.js +120 -0
- package/dist/lib/long-task-status-projection.d.ts +4 -1
- package/dist/lib/long-task-status-projection.js +63 -3
- package/dist/lib/long-task-status-v2.d.ts +11 -1
- package/dist/lib/long-task-status-v2.js +25 -3
- package/dist/lib/long-task-target-policy.d.ts +6 -0
- package/dist/lib/long-task-target-policy.js +127 -0
- package/dist/lib/migrations.js +29 -0
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +62 -8
- package/migrations/README.md +15 -8
- package/package.json +2 -2
- package/source-mappings.yaml +25 -25
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { array, fail, key, literal, object, parseEnvironmentRequirements, PROOF_SURFACES, repositoryCwd, repositoryFile, repositoryPatterns, string, strings, } from "./long-task-delivery-shape.js";
|
|
1
|
+
import { array, EVIDENCE_CAPABILITIES, fail, key, JOURNEY_ROLES, literal, object, parseEnvironmentRequirements, PROOF_SURFACES, repositoryCwd, repositoryFile, repositoryPatterns, string, strings, } from "./long-task-delivery-shape.js";
|
|
2
2
|
export function parseCheck(value, label) {
|
|
3
|
-
const row = object(value, label, [
|
|
3
|
+
const row = object(value, label, [
|
|
4
|
+
"key",
|
|
5
|
+
"journey_roles",
|
|
6
|
+
"execution_target",
|
|
7
|
+
"scenario",
|
|
8
|
+
"proof_surface",
|
|
9
|
+
"runner",
|
|
10
|
+
"verification_inputs",
|
|
11
|
+
], [
|
|
4
12
|
"input_paths",
|
|
5
13
|
"expected_output_paths",
|
|
6
14
|
"artifact_globs",
|
|
@@ -8,8 +16,19 @@ export function parseCheck(value, label) {
|
|
|
8
16
|
"negative_assertions",
|
|
9
17
|
"environment_requirements",
|
|
10
18
|
]);
|
|
19
|
+
const executionTarget = object(row.execution_target, `${label}.execution_target`, ["target_ref", "entrypoint"]);
|
|
20
|
+
const scenario = object(row.scenario, `${label}.scenario`, ["given", "when"]);
|
|
11
21
|
return {
|
|
12
22
|
key: key(row.key, `${label}.key`),
|
|
23
|
+
journey_roles: array(row.journey_roles, `${label}.journey_roles`).map((item, index) => literal(item, JOURNEY_ROLES, `${label}.journey_roles[${index}]`)),
|
|
24
|
+
execution_target: {
|
|
25
|
+
target_ref: key(executionTarget.target_ref, `${label}.execution_target.target_ref`),
|
|
26
|
+
entrypoint: literal(executionTarget.entrypoint, ["root", "internal"], `${label}.execution_target.entrypoint`),
|
|
27
|
+
},
|
|
28
|
+
scenario: {
|
|
29
|
+
given: parseScenarioSteps(scenario.given, `${label}.scenario.given`),
|
|
30
|
+
when: parseScenarioSteps(scenario.when, `${label}.scenario.when`),
|
|
31
|
+
},
|
|
13
32
|
proof_surface: literal(row.proof_surface, PROOF_SURFACES, `${label}.proof_surface`),
|
|
14
33
|
runner: parseRunner(row.runner, `${label}.runner`),
|
|
15
34
|
verification_inputs: repositoryPatterns(row.verification_inputs, `${label}.verification_inputs`),
|
|
@@ -70,7 +89,7 @@ function parseRunner(value, label) {
|
|
|
70
89
|
function parseAssertions(value, label) {
|
|
71
90
|
return array(value, label).map((item, index) => {
|
|
72
91
|
const itemLabel = `${label}[${index}]`;
|
|
73
|
-
const row = object(item, itemLabel, ["key", "claims", "observation", "operator"], ["criterion", "expected"]);
|
|
92
|
+
const row = object(item, itemLabel, ["key", "claims", "observation", "operator", "evidence_capabilities"], ["criterion", "expected"]);
|
|
74
93
|
const operator = literal(row.operator, [
|
|
75
94
|
"equals",
|
|
76
95
|
"not_equals",
|
|
@@ -103,6 +122,7 @@ function parseAssertions(value, label) {
|
|
|
103
122
|
: {}),
|
|
104
123
|
claims: strings(row.claims, `${itemLabel}.claims`),
|
|
105
124
|
observation: string(row.observation, `${itemLabel}.observation`),
|
|
125
|
+
evidence_capabilities: array(row.evidence_capabilities, `${itemLabel}.evidence_capabilities`).map((capability, capabilityIndex) => literal(capability, EVIDENCE_CAPABILITIES, `${itemLabel}.evidence_capabilities[${capabilityIndex}]`)),
|
|
106
126
|
operator,
|
|
107
127
|
};
|
|
108
128
|
return isBinaryAssertionOperator(operator)
|
|
@@ -113,6 +133,16 @@ function parseAssertions(value, label) {
|
|
|
113
133
|
};
|
|
114
134
|
});
|
|
115
135
|
}
|
|
136
|
+
function parseScenarioSteps(value, label) {
|
|
137
|
+
return array(value, label).map((item, index) => {
|
|
138
|
+
const itemLabel = `${label}[${index}]`;
|
|
139
|
+
const row = object(item, itemLabel, ["key", "statement"]);
|
|
140
|
+
return {
|
|
141
|
+
key: key(row.key, `${itemLabel}.key`),
|
|
142
|
+
statement: string(row.statement, `${itemLabel}.statement`),
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
}
|
|
116
146
|
function isBinaryAssertionOperator(operator) {
|
|
117
147
|
return !["exists", "truthy", "falsy"].includes(operator);
|
|
118
148
|
}
|
|
@@ -5,14 +5,28 @@ export function generateClaims(outcome) {
|
|
|
5
5
|
claims.push(claim(outcome.key, `requirement.${requirement.key}`, "requirement", requirement.required_proof_surfaces));
|
|
6
6
|
for (const control of outcome.product.controls) {
|
|
7
7
|
const fields = [
|
|
8
|
+
["surface", control.surface],
|
|
9
|
+
["region", control.region],
|
|
8
10
|
["location", control.location],
|
|
11
|
+
["control_type", control.control_type],
|
|
12
|
+
["label_content", control.label_content],
|
|
13
|
+
["user_task", control.user_task],
|
|
14
|
+
["visibility", control.visibility],
|
|
15
|
+
["availability", control.availability],
|
|
9
16
|
["trigger", control.trigger],
|
|
10
17
|
["input", control.input],
|
|
18
|
+
["validation", control.validation],
|
|
19
|
+
["default_value", control.default_value],
|
|
20
|
+
["interaction", control.interaction],
|
|
21
|
+
["navigation_result", control.navigation_result],
|
|
11
22
|
["loading", control.loading_state],
|
|
12
23
|
["empty", control.empty_state],
|
|
13
24
|
["success", control.success_state],
|
|
14
25
|
["failure", control.failure_state],
|
|
26
|
+
["recovery", control.recovery],
|
|
27
|
+
["permission", control.permission],
|
|
15
28
|
["feedback", control.feedback],
|
|
29
|
+
["accessibility", control.accessibility],
|
|
16
30
|
];
|
|
17
31
|
for (const [field, value] of fields)
|
|
18
32
|
if (value.trim())
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CompiledCheckV2, DeliveryContractV2, EffectiveRiskLevel } from "./long-task-delivery-types.js";
|
|
2
|
+
type Reporter = (message: string) => void;
|
|
3
|
+
export declare function semanticConformanceRequired(contract: DeliveryContractV2, _effectiveRisk?: EffectiveRiskLevel): boolean;
|
|
4
|
+
export declare function validateSemanticConformance(contract: DeliveryContractV2, effectiveRisk: EffectiveRiskLevel, compiledChecks: CompiledCheckV2[], report?: Reporter): void;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function semanticConformanceRequired(contract, _effectiveRisk) {
|
|
2
|
+
const productFamilies = new Set(contract.task.execution_targets
|
|
3
|
+
.filter((target) => contract.task.target_profile.required_target_refs.includes(target.key))
|
|
4
|
+
.map((target) => target.runtime_family));
|
|
5
|
+
return (contract.risk.facts.weak_observability.length > 0 &&
|
|
6
|
+
(productFamilies.size > 1 || contract.stages.length > 1));
|
|
7
|
+
}
|
|
8
|
+
export function validateSemanticConformance(contract, effectiveRisk, compiledChecks, report) {
|
|
9
|
+
const declared = contract.global.acceptance.checks.filter((check) => check.journey_roles.includes("conformance"));
|
|
10
|
+
if (semanticConformanceRequired(contract, effectiveRisk) &&
|
|
11
|
+
!declared.length) {
|
|
12
|
+
issue(report, "semantic_conformance_check_required", contract.task.id);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const check of declared) {
|
|
16
|
+
if (check.runner.effect !== "read_only")
|
|
17
|
+
issue(report, "conformance_check_must_be_read_only", check.key);
|
|
18
|
+
if (![...check.positive_assertions, ...check.negative_assertions].some((assertion) => assertion.evidence_capabilities.includes("target_runtime")))
|
|
19
|
+
issue(report, "conformance_target_runtime_evidence_required", check.key);
|
|
20
|
+
const compiled = compiledChecks.find((candidate) => candidate.outcome_key === null && candidate.key === check.key);
|
|
21
|
+
if (!compiled)
|
|
22
|
+
continue;
|
|
23
|
+
if (compiledChecks.some((candidate) => candidate.internal_id !== compiled.internal_id &&
|
|
24
|
+
candidate.outcome_key !== null &&
|
|
25
|
+
candidate.raw_execution_identity === compiled.raw_execution_identity))
|
|
26
|
+
issue(report, "conformance_raw_execution_must_be_independent", check.key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function issue(report, code, detail) {
|
|
30
|
+
const message = `delivery_contract_invalid:${code}:${detail}`;
|
|
31
|
+
if (report)
|
|
32
|
+
report(message);
|
|
33
|
+
else
|
|
34
|
+
throw new Error(message);
|
|
35
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LongTaskRiskFacts, RequestedRiskLevel } from "./long-task-risk-types.js";
|
|
2
2
|
import type { CounterfactualControlV2, GlobalCounterfactualControlV2 } from "./long-task-counterfactual-types.js";
|
|
3
|
+
import type { CheckExecutionTargetV2, DeliveryJourneyRoleV2, DeliveryScenarioV2, DeliveryStageV2, EvidenceCapabilityV2, ExecutionTargetV2, ExternalConfirmationKindV2, KeyedStatementV2, TargetProfileV2 } from "./long-task-semantic-contract-types.js";
|
|
3
4
|
export type SourceClaimDispositionV2 = {
|
|
4
5
|
type: "claim";
|
|
5
6
|
refs: string[];
|
|
@@ -28,10 +29,6 @@ export interface SourceClaimV2 {
|
|
|
28
29
|
statement: string;
|
|
29
30
|
disposition: SourceClaimDispositionV2;
|
|
30
31
|
}
|
|
31
|
-
export interface KeyedStatementV2 {
|
|
32
|
-
key: string;
|
|
33
|
-
statement: string;
|
|
34
|
-
}
|
|
35
32
|
export interface KeyedPathV2 {
|
|
36
33
|
key: string;
|
|
37
34
|
path: string;
|
|
@@ -40,6 +37,9 @@ export interface ExternalConfirmationV2 {
|
|
|
40
37
|
key: string;
|
|
41
38
|
description: string;
|
|
42
39
|
owner: string;
|
|
40
|
+
kind: ExternalConfirmationKindV2;
|
|
41
|
+
impact_claims: string[];
|
|
42
|
+
blocks_target: boolean;
|
|
43
43
|
}
|
|
44
44
|
export type ProofSurface = "ui_browser" | "runtime_behavior" | "api_contract" | "data_state" | "security_boundary" | "population_coverage" | "implementation_structure";
|
|
45
45
|
export type RunnerType = "package_script" | "project_binary" | "node_oracle" | "playwright_test";
|
|
@@ -51,6 +51,7 @@ interface DeliveryAssertionBaseV2 {
|
|
|
51
51
|
criterion?: string;
|
|
52
52
|
claims: string[];
|
|
53
53
|
observation: string;
|
|
54
|
+
evidence_capabilities: EvidenceCapabilityV2[];
|
|
54
55
|
}
|
|
55
56
|
export type DeliveryAssertionV2 = (DeliveryAssertionBaseV2 & {
|
|
56
57
|
operator: PresenceOrUnaryAssertionOperator;
|
|
@@ -86,6 +87,9 @@ export type EnvironmentRequirementV2 = {
|
|
|
86
87
|
};
|
|
87
88
|
export interface DeliveryCheckV2 {
|
|
88
89
|
key: string;
|
|
90
|
+
journey_roles: DeliveryJourneyRoleV2[];
|
|
91
|
+
execution_target: CheckExecutionTargetV2;
|
|
92
|
+
scenario: DeliveryScenarioV2;
|
|
89
93
|
proof_surface: ProofSurface;
|
|
90
94
|
runner: DeliveryRunnerV2;
|
|
91
95
|
verification_inputs: string[];
|
|
@@ -98,14 +102,28 @@ export interface DeliveryCheckV2 {
|
|
|
98
102
|
}
|
|
99
103
|
export interface DeliveryControlV2 {
|
|
100
104
|
key: string;
|
|
105
|
+
surface: string;
|
|
106
|
+
region: string;
|
|
101
107
|
location: string;
|
|
108
|
+
control_type: string;
|
|
109
|
+
label_content: string;
|
|
110
|
+
user_task: string;
|
|
111
|
+
visibility: string;
|
|
112
|
+
availability: string;
|
|
102
113
|
trigger: string;
|
|
103
114
|
input: string;
|
|
115
|
+
validation: string;
|
|
116
|
+
default_value: string;
|
|
117
|
+
interaction: string;
|
|
118
|
+
navigation_result: string;
|
|
104
119
|
loading_state: string;
|
|
105
120
|
empty_state: string;
|
|
106
121
|
success_state: string;
|
|
107
122
|
failure_state: string;
|
|
123
|
+
recovery: string;
|
|
124
|
+
permission: string;
|
|
108
125
|
feedback: string;
|
|
126
|
+
accessibility: string;
|
|
109
127
|
}
|
|
110
128
|
interface DeliveryRequirementV2 extends KeyedStatementV2 {
|
|
111
129
|
required_proof_surfaces: ProofSurface[];
|
|
@@ -144,9 +162,12 @@ export interface PopulationRequirementV2 {
|
|
|
144
162
|
export interface DeliveryOutcomeV2 {
|
|
145
163
|
key: string;
|
|
146
164
|
title: string;
|
|
165
|
+
stage: string;
|
|
147
166
|
depends_on: string[];
|
|
148
167
|
product: {
|
|
149
168
|
observable_result: string;
|
|
169
|
+
success_path_required: boolean;
|
|
170
|
+
degradation_path_required: boolean;
|
|
150
171
|
owner: DeliveryOwnerV2;
|
|
151
172
|
requirements: DeliveryRequirementV2[];
|
|
152
173
|
owner_surfaces: string[];
|
|
@@ -174,11 +195,14 @@ export interface DeliveryContractV2 {
|
|
|
174
195
|
id: string;
|
|
175
196
|
title: string;
|
|
176
197
|
goal: string;
|
|
198
|
+
target_profile: TargetProfileV2;
|
|
199
|
+
execution_targets: ExecutionTargetV2[];
|
|
177
200
|
source_paths: string[];
|
|
178
201
|
context_refs: string[];
|
|
179
202
|
context_snapshot_mode: "referenced" | "full";
|
|
180
203
|
};
|
|
181
204
|
source_claims: SourceClaimV2[];
|
|
205
|
+
stages: DeliveryStageV2[];
|
|
182
206
|
risk: {
|
|
183
207
|
requested_level: RequestedRiskLevel;
|
|
184
208
|
facts: LongTaskRiskFacts;
|
|
@@ -114,6 +114,7 @@ export async function compileDeliveryContract(workdirInput, projectRootInput = p
|
|
|
114
114
|
task: contract.task,
|
|
115
115
|
risk: contract.risk,
|
|
116
116
|
source_claims: contract.source_claims,
|
|
117
|
+
stages: contract.stages,
|
|
117
118
|
global: {
|
|
118
119
|
product: contract.global.product,
|
|
119
120
|
technical: contract.global.technical,
|
|
@@ -5,8 +5,9 @@ import { validateDeliveryContractStructure } from "./long-task-delivery-validati
|
|
|
5
5
|
import { parseOutcome, parseOutcomeFragment, safeFragmentPath, } from "./long-task-outcome-parser.js";
|
|
6
6
|
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
7
7
|
import { array, literal, object, parseSourceClaims, strings, } from "./long-task-delivery-shape.js";
|
|
8
|
-
import { parseGlobal, parseRisk, parseTask } from "./long-task-root-shape.js";
|
|
8
|
+
import { parseGlobal, parseRisk, parseStages, parseTask, } from "./long-task-root-shape.js";
|
|
9
9
|
import { repositoryRoot } from "./long-task-workspace.js";
|
|
10
|
+
import { assertNoSemanticDriftMigration, semanticDriftMigrationFields, } from "./long-task-semantic-drift-migration.js";
|
|
10
11
|
export const DELIVERY_CONTRACT_FILE = "delivery-contract.yaml";
|
|
11
12
|
export async function parseDeliveryContract(workdir) {
|
|
12
13
|
return (await parseDeliveryContractBundle(workdir)).contract;
|
|
@@ -75,7 +76,8 @@ function parseRoot(raw, bundle) {
|
|
|
75
76
|
decoded.schema_version ===
|
|
76
77
|
"long-task-delivery-v1")
|
|
77
78
|
throw new Error("long_task_delivery_v1_retired_use_v2");
|
|
78
|
-
|
|
79
|
+
assertNoSemanticDriftMigration(semanticDriftMigrationFields(decoded));
|
|
80
|
+
return object(decoded, "$", ["schema_version", "task", "source_claims", "stages", "risk", "global"], bundle ? ["outcomes", "outcome_files"] : ["outcomes"]);
|
|
79
81
|
}
|
|
80
82
|
function parseContractRoot(root, outcomes) {
|
|
81
83
|
literal(root.schema_version, ["long-task-delivery-v2"], "schema_version");
|
|
@@ -83,6 +85,7 @@ function parseContractRoot(root, outcomes) {
|
|
|
83
85
|
schema_version: "long-task-delivery-v2",
|
|
84
86
|
task: parseTask(root.task),
|
|
85
87
|
source_claims: parseSourceClaims(root.source_claims, "source_claims"),
|
|
88
|
+
stages: parseStages(root.stages),
|
|
86
89
|
risk: parseRisk(root.risk),
|
|
87
90
|
global: parseGlobal(root.global),
|
|
88
91
|
outcomes,
|
|
@@ -2,7 +2,9 @@ export * from "./long-task-contract-types.js";
|
|
|
2
2
|
export * from "./long-task-counterfactual-types.js";
|
|
3
3
|
export * from "./long-task-authority-types.js";
|
|
4
4
|
export * from "./long-task-evidence-adapter-types.js";
|
|
5
|
+
export * from "./long-task-evidence-capability-types.js";
|
|
5
6
|
export * from "./long-task-risk-types.js";
|
|
6
7
|
export * from "./long-task-runtime-types.js";
|
|
8
|
+
export * from "./long-task-semantic-contract-types.js";
|
|
7
9
|
export * from "./long-task-source-authority-types.js";
|
|
8
10
|
export * from "./long-task-workspace-runtime-types.js";
|
|
@@ -2,7 +2,9 @@ export * from "./long-task-contract-types.js";
|
|
|
2
2
|
export * from "./long-task-counterfactual-types.js";
|
|
3
3
|
export * from "./long-task-authority-types.js";
|
|
4
4
|
export * from "./long-task-evidence-adapter-types.js";
|
|
5
|
+
export * from "./long-task-evidence-capability-types.js";
|
|
5
6
|
export * from "./long-task-risk-types.js";
|
|
6
7
|
export * from "./long-task-runtime-types.js";
|
|
8
|
+
export * from "./long-task-semantic-contract-types.js";
|
|
7
9
|
export * from "./long-task-source-authority-types.js";
|
|
8
10
|
export * from "./long-task-workspace-runtime-types.js";
|
|
@@ -4,6 +4,9 @@ import { proveRepositoryPatternSubset } from "./long-task-paths.js";
|
|
|
4
4
|
import { validateSourceClaimMappings } from "./long-task-source-claim-validation.js";
|
|
5
5
|
import { validateDeclaredCheckSafety } from "./long-task-claim-proof-policy.js";
|
|
6
6
|
import { validateEvidenceAdapterCompatibility } from "./long-task-evidence-adapter-policy.js";
|
|
7
|
+
import { validateEvidenceCapabilityDeclarations } from "./long-task-evidence-capability-policy.js";
|
|
8
|
+
import { validateDeliveryStages } from "./long-task-stage-policy.js";
|
|
9
|
+
import { validateExecutionTargets, validateExternalConfirmationImpacts, } from "./long-task-target-policy.js";
|
|
7
10
|
export function validateDeliveryContractStructure(contract) {
|
|
8
11
|
validateUniqueKeys(contract);
|
|
9
12
|
validateDependencies(contract);
|
|
@@ -15,12 +18,19 @@ export function validateDeliveryContractStructure(contract) {
|
|
|
15
18
|
});
|
|
16
19
|
validateSourceClaimMappings(contract, claims);
|
|
17
20
|
assertCompiledClaimsCovered(claims);
|
|
21
|
+
validateDeliveryStages(contract);
|
|
22
|
+
validateExecutionTargets(contract);
|
|
23
|
+
validateEvidenceCapabilityDeclarations(contract);
|
|
24
|
+
validateExternalConfirmationImpacts(contract, claims);
|
|
18
25
|
}
|
|
19
26
|
export function deliveryContractStructureDiagnostics(contract) {
|
|
20
27
|
const diagnostics = [];
|
|
21
28
|
const report = (message) => diagnostics.push(message);
|
|
22
29
|
validateUniqueKeys(contract, report);
|
|
23
30
|
validateDependencies(contract, report);
|
|
31
|
+
validateDeliveryStages(contract, report);
|
|
32
|
+
validateExecutionTargets(contract, report);
|
|
33
|
+
validateEvidenceCapabilityDeclarations(contract, report);
|
|
24
34
|
validateOwnerAndBindings(contract, report);
|
|
25
35
|
validateDeclaredCheckSafety(contract, report);
|
|
26
36
|
validateEvidenceAdapters(contract, report);
|
|
@@ -30,6 +40,7 @@ export function deliveryContractStructureDiagnostics(contract) {
|
|
|
30
40
|
});
|
|
31
41
|
if (claims) {
|
|
32
42
|
validateSourceClaimMappings(contract, claims, report);
|
|
43
|
+
validateExternalConfirmationImpacts(contract, claims, report);
|
|
33
44
|
capture(diagnostics, () => assertCompiledClaimsCovered(claims));
|
|
34
45
|
}
|
|
35
46
|
return [...new Set(diagnostics)];
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
export function decodeEvidenceCapabilityRecords(value) {
|
|
2
|
+
if (!Array.isArray(value))
|
|
3
|
+
throw invalidRecord("must_be_array");
|
|
4
|
+
return value.map((item, index) => decodeRecord(item, index));
|
|
5
|
+
}
|
|
6
|
+
function decodeRecord(value, index) {
|
|
7
|
+
const label = `evidence_records[${index}]`;
|
|
8
|
+
const row = record(value, label);
|
|
9
|
+
const assertionKey = key(row.assertion_key, `${label}.assertion_key`);
|
|
10
|
+
const capability = nonEmpty(row.capability, `${label}.capability`);
|
|
11
|
+
const base = { assertion_key: assertionKey };
|
|
12
|
+
switch (capability) {
|
|
13
|
+
case "interaction_trace":
|
|
14
|
+
exact(row, label, [
|
|
15
|
+
"assertion_key",
|
|
16
|
+
"capability",
|
|
17
|
+
"target_ref",
|
|
18
|
+
"given_keys",
|
|
19
|
+
"action_keys",
|
|
20
|
+
]);
|
|
21
|
+
return {
|
|
22
|
+
...base,
|
|
23
|
+
capability,
|
|
24
|
+
target_ref: key(row.target_ref, `${label}.target_ref`),
|
|
25
|
+
given_keys: keys(row.given_keys, `${label}.given_keys`),
|
|
26
|
+
action_keys: keys(row.action_keys, `${label}.action_keys`),
|
|
27
|
+
};
|
|
28
|
+
case "state_delta":
|
|
29
|
+
exact(row, label, [
|
|
30
|
+
"assertion_key",
|
|
31
|
+
"capability",
|
|
32
|
+
"before_sha256",
|
|
33
|
+
"after_sha256",
|
|
34
|
+
"changed_fields",
|
|
35
|
+
]);
|
|
36
|
+
return {
|
|
37
|
+
...base,
|
|
38
|
+
capability,
|
|
39
|
+
before_sha256: sha(row.before_sha256, `${label}.before_sha256`),
|
|
40
|
+
after_sha256: sha(row.after_sha256, `${label}.after_sha256`),
|
|
41
|
+
changed_fields: strings(row.changed_fields, `${label}.changed_fields`),
|
|
42
|
+
};
|
|
43
|
+
case "cross_surface_consistency":
|
|
44
|
+
exact(row, label, ["assertion_key", "capability", "surfaces"]);
|
|
45
|
+
return {
|
|
46
|
+
...base,
|
|
47
|
+
capability,
|
|
48
|
+
surfaces: array(row.surfaces, `${label}.surfaces`).map((item, surfaceIndex) => {
|
|
49
|
+
const surfaceLabel = `${label}.surfaces[${surfaceIndex}]`;
|
|
50
|
+
const surface = record(item, surfaceLabel);
|
|
51
|
+
exact(surface, surfaceLabel, [
|
|
52
|
+
"surface_ref",
|
|
53
|
+
"target_ref",
|
|
54
|
+
"state_sha256",
|
|
55
|
+
]);
|
|
56
|
+
return {
|
|
57
|
+
surface_ref: key(surface.surface_ref, `${surfaceLabel}.surface_ref`),
|
|
58
|
+
target_ref: key(surface.target_ref, `${surfaceLabel}.target_ref`),
|
|
59
|
+
state_sha256: sha(surface.state_sha256, `${surfaceLabel}.state_sha256`),
|
|
60
|
+
};
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
case "durable_readback":
|
|
64
|
+
exact(row, label, [
|
|
65
|
+
"assertion_key",
|
|
66
|
+
"capability",
|
|
67
|
+
"write_session_id",
|
|
68
|
+
"read_session_id",
|
|
69
|
+
"written_sha256",
|
|
70
|
+
"read_sha256",
|
|
71
|
+
]);
|
|
72
|
+
return {
|
|
73
|
+
...base,
|
|
74
|
+
capability,
|
|
75
|
+
write_session_id: nonEmpty(row.write_session_id, `${label}.write_session_id`),
|
|
76
|
+
read_session_id: nonEmpty(row.read_session_id, `${label}.read_session_id`),
|
|
77
|
+
written_sha256: sha(row.written_sha256, `${label}.written_sha256`),
|
|
78
|
+
read_sha256: sha(row.read_sha256, `${label}.read_sha256`),
|
|
79
|
+
};
|
|
80
|
+
case "boundary_invocation":
|
|
81
|
+
exact(row, label, [
|
|
82
|
+
"assertion_key",
|
|
83
|
+
"capability",
|
|
84
|
+
"boundary",
|
|
85
|
+
"invocation_id",
|
|
86
|
+
"request_sha256",
|
|
87
|
+
"observer_target_ref",
|
|
88
|
+
]);
|
|
89
|
+
return {
|
|
90
|
+
...base,
|
|
91
|
+
capability,
|
|
92
|
+
boundary: nonEmpty(row.boundary, `${label}.boundary`),
|
|
93
|
+
invocation_id: nonEmpty(row.invocation_id, `${label}.invocation_id`),
|
|
94
|
+
request_sha256: sha(row.request_sha256, `${label}.request_sha256`),
|
|
95
|
+
observer_target_ref: key(row.observer_target_ref, `${label}.observer_target_ref`),
|
|
96
|
+
};
|
|
97
|
+
case "external_side_effect":
|
|
98
|
+
exact(row, label, [
|
|
99
|
+
"assertion_key",
|
|
100
|
+
"capability",
|
|
101
|
+
"boundary",
|
|
102
|
+
"effect_id",
|
|
103
|
+
"effect_sha256",
|
|
104
|
+
"observer_target_ref",
|
|
105
|
+
]);
|
|
106
|
+
return {
|
|
107
|
+
...base,
|
|
108
|
+
capability,
|
|
109
|
+
boundary: nonEmpty(row.boundary, `${label}.boundary`),
|
|
110
|
+
effect_id: nonEmpty(row.effect_id, `${label}.effect_id`),
|
|
111
|
+
effect_sha256: sha(row.effect_sha256, `${label}.effect_sha256`),
|
|
112
|
+
observer_target_ref: key(row.observer_target_ref, `${label}.observer_target_ref`),
|
|
113
|
+
};
|
|
114
|
+
case "failure_injection":
|
|
115
|
+
exact(row, label, [
|
|
116
|
+
"assertion_key",
|
|
117
|
+
"capability",
|
|
118
|
+
"fault",
|
|
119
|
+
"failure_observed",
|
|
120
|
+
"recovery_state_sha256",
|
|
121
|
+
]);
|
|
122
|
+
if (row.failure_observed !== true)
|
|
123
|
+
throw invalidRecord(`${label}.failure_observed`);
|
|
124
|
+
return {
|
|
125
|
+
...base,
|
|
126
|
+
capability,
|
|
127
|
+
fault: nonEmpty(row.fault, `${label}.fault`),
|
|
128
|
+
failure_observed: true,
|
|
129
|
+
recovery_state_sha256: sha(row.recovery_state_sha256, `${label}.recovery_state_sha256`),
|
|
130
|
+
};
|
|
131
|
+
case "visual_render":
|
|
132
|
+
exact(row, label, [
|
|
133
|
+
"assertion_key",
|
|
134
|
+
"capability",
|
|
135
|
+
"artifact_path",
|
|
136
|
+
"artifact_sha256",
|
|
137
|
+
]);
|
|
138
|
+
return {
|
|
139
|
+
...base,
|
|
140
|
+
capability,
|
|
141
|
+
artifact_path: nonEmpty(row.artifact_path, `${label}.artifact_path`),
|
|
142
|
+
artifact_sha256: sha(row.artifact_sha256, `${label}.artifact_sha256`),
|
|
143
|
+
};
|
|
144
|
+
case "target_runtime":
|
|
145
|
+
exact(row, label, [
|
|
146
|
+
"assertion_key",
|
|
147
|
+
"capability",
|
|
148
|
+
"target_ref",
|
|
149
|
+
"root_entrypoint",
|
|
150
|
+
"session_id",
|
|
151
|
+
"cold_start",
|
|
152
|
+
]);
|
|
153
|
+
if (typeof row.cold_start !== "boolean")
|
|
154
|
+
throw invalidRecord(`${label}.cold_start`);
|
|
155
|
+
return {
|
|
156
|
+
...base,
|
|
157
|
+
capability,
|
|
158
|
+
target_ref: key(row.target_ref, `${label}.target_ref`),
|
|
159
|
+
root_entrypoint: nonEmpty(row.root_entrypoint, `${label}.root_entrypoint`),
|
|
160
|
+
session_id: nonEmpty(row.session_id, `${label}.session_id`),
|
|
161
|
+
cold_start: row.cold_start,
|
|
162
|
+
};
|
|
163
|
+
case "input_variation":
|
|
164
|
+
exact(row, label, [
|
|
165
|
+
"assertion_key",
|
|
166
|
+
"capability",
|
|
167
|
+
"cases",
|
|
168
|
+
"failure_case_observed",
|
|
169
|
+
]);
|
|
170
|
+
if (typeof row.failure_case_observed !== "boolean")
|
|
171
|
+
throw invalidRecord(`${label}.failure_case_observed`);
|
|
172
|
+
return {
|
|
173
|
+
...base,
|
|
174
|
+
capability,
|
|
175
|
+
cases: array(row.cases, `${label}.cases`).map((item, caseIndex) => {
|
|
176
|
+
const caseLabel = `${label}.cases[${caseIndex}]`;
|
|
177
|
+
const entry = record(item, caseLabel);
|
|
178
|
+
exact(entry, caseLabel, ["input_sha256", "output_sha256"]);
|
|
179
|
+
return {
|
|
180
|
+
input_sha256: sha(entry.input_sha256, `${caseLabel}.input_sha256`),
|
|
181
|
+
output_sha256: sha(entry.output_sha256, `${caseLabel}.output_sha256`),
|
|
182
|
+
};
|
|
183
|
+
}),
|
|
184
|
+
failure_case_observed: row.failure_case_observed,
|
|
185
|
+
};
|
|
186
|
+
default:
|
|
187
|
+
throw invalidRecord(`${label}.capability_unsupported:${capability}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function invalidRecord(detail) {
|
|
191
|
+
return new Error(`check_evidence_records_invalid:${detail}`);
|
|
192
|
+
}
|
|
193
|
+
function record(value, label) {
|
|
194
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
195
|
+
throw invalidRecord(label);
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
function exact(row, label, fields) {
|
|
199
|
+
const allowed = new Set(fields);
|
|
200
|
+
if (fields.some((field) => !Object.hasOwn(row, field)) ||
|
|
201
|
+
Object.keys(row).some((field) => !allowed.has(field)))
|
|
202
|
+
throw invalidRecord(`${label}.shape`);
|
|
203
|
+
}
|
|
204
|
+
function array(value, label) {
|
|
205
|
+
if (!Array.isArray(value))
|
|
206
|
+
throw invalidRecord(label);
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
function nonEmpty(value, label) {
|
|
210
|
+
if (typeof value !== "string" || !value.trim())
|
|
211
|
+
throw invalidRecord(label);
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
function key(value, label) {
|
|
215
|
+
const result = nonEmpty(value, label);
|
|
216
|
+
if (!/^[a-z0-9][a-z0-9-]*$/u.test(result))
|
|
217
|
+
throw invalidRecord(label);
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
function strings(value, label) {
|
|
221
|
+
return array(value, label).map((item, index) => nonEmpty(item, `${label}[${index}]`));
|
|
222
|
+
}
|
|
223
|
+
function keys(value, label) {
|
|
224
|
+
return array(value, label).map((item, index) => key(item, `${label}[${index}]`));
|
|
225
|
+
}
|
|
226
|
+
function sha(value, label) {
|
|
227
|
+
const result = nonEmpty(value, label);
|
|
228
|
+
if (!/^[a-f0-9]{64}$/u.test(result))
|
|
229
|
+
throw invalidRecord(label);
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CompiledCheckV2, DeliveryContractV2, EvidenceCapabilityRecordV2, LongTaskFindingV2 } from "./long-task-delivery-types.js";
|
|
2
|
+
export { decodeEvidenceCapabilityRecords } from "./long-task-evidence-capability-codec.js";
|
|
3
|
+
type Reporter = (message: string) => void;
|
|
4
|
+
export declare function validateEvidenceCapabilityDeclarations(contract: DeliveryContractV2, report?: Reporter): void;
|
|
5
|
+
export declare function evaluateEvidenceCapabilities(check: CompiledCheckV2, records: EvidenceCapabilityRecordV2[], artifactHashes: Record<string, string>): {
|
|
6
|
+
complete: Record<string, boolean>;
|
|
7
|
+
findings: LongTaskFindingV2[];
|
|
8
|
+
};
|