project-tiny-context-harness 0.8.1 → 0.8.3
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 +26 -20
- package/assets/README.md +115 -36
- package/assets/README.zh-CN.md +33 -27
- package/assets/agents/AGENTS_CORE.md +6 -6
- package/assets/skills/context_development_engineer/SKILL.md +6 -6
- package/assets/skills/context_uiux_design/SKILL.md +5 -5
- package/assets/skills/design-resource-authoring/SKILL.md +4 -3
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +9 -6
- package/assets/skills/design-resource-authoring/references/resource-selection.md +3 -2
- package/assets/skills/long-task-workflow/SKILL.md +16 -16
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +8 -6
- package/assets/skills/long-task-workflow/references/contract-authoring.md +18 -14
- package/assets/skills/long-task-workflow/references/evidence-design.md +15 -14
- package/assets/skills/long-task-workflow/references/source-authoring.md +12 -9
- package/assets/skills/source-plan-authoring/SKILL.md +1 -1
- package/dist/commands/long-task-authoring.js +83 -9
- package/dist/lib/context-graph-snapshot.js +7 -0
- package/dist/lib/design-resource-fact-policy.d.ts +25 -0
- package/dist/lib/design-resource-fact-policy.js +35 -0
- package/dist/lib/design-resource-handoff-shape-evidence.d.ts +3 -1
- package/dist/lib/design-resource-handoff-shape-evidence.js +60 -0
- package/dist/lib/design-resource-handoff-shape.js +5 -1
- package/dist/lib/design-resource-handoff-types.d.ts +29 -0
- package/dist/lib/design-resource-handoff-validation-coverage.d.ts +1 -1
- package/dist/lib/design-resource-handoff-validation-coverage.js +42 -14
- package/dist/lib/design-resource-handoff-validation-facts.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-facts.js +97 -0
- package/dist/lib/design-resource-handoff-validation-structure.js +2 -0
- package/dist/lib/design-resource-handoff-validation.js +10 -1
- package/dist/lib/execution-target-capabilities.d.ts +2 -0
- package/dist/lib/execution-target-capabilities.js +31 -0
- package/dist/lib/long-task-acceptance-shape.js +81 -20
- package/dist/lib/long-task-applicability-shape.d.ts +4 -0
- package/dist/lib/long-task-applicability-shape.js +54 -0
- package/dist/lib/long-task-assertions-v2.js +8 -0
- package/dist/lib/long-task-authoring-preflight-diagnostics.js +5 -0
- package/dist/lib/long-task-authoring-preflight-repair-order.js +3 -0
- package/dist/lib/long-task-authoring-preflight.js +12 -8
- package/dist/lib/long-task-authority-materials.js +46 -4
- package/dist/lib/long-task-authority-policy.d.ts +54 -0
- package/dist/lib/long-task-authority-policy.js +61 -0
- package/dist/lib/long-task-authority-types.d.ts +12 -2
- package/dist/lib/long-task-authority.js +9 -2
- package/dist/lib/long-task-check-shape.js +6 -1
- package/dist/lib/long-task-claim-definitions.js +27 -42
- package/dist/lib/long-task-claims.js +275 -146
- package/dist/lib/long-task-contract-types.d.ts +42 -8
- package/dist/lib/long-task-control-fields.d.ts +12 -0
- package/dist/lib/long-task-control-fields.js +66 -0
- package/dist/lib/long-task-control-types.d.ts +1 -0
- package/dist/lib/long-task-control-types.js +1 -0
- package/dist/lib/long-task-counterfactual-claim-policy.js +7 -0
- package/dist/lib/long-task-counterfactual-types.d.ts +12 -0
- package/dist/lib/long-task-delivery-compiler.js +1 -0
- package/dist/lib/long-task-delivery-preflight.js +24 -0
- package/dist/lib/long-task-delivery-shape.d.ts +1 -0
- package/dist/lib/long-task-delivery-shape.js +1 -0
- package/dist/lib/long-task-delivery-types.d.ts +1 -0
- package/dist/lib/long-task-delivery-types.js +1 -0
- package/dist/lib/long-task-delivery-validation.js +46 -0
- package/dist/lib/long-task-design-resource-handoff.js +67 -13
- package/dist/lib/long-task-evidence-capability-codec.js +47 -0
- package/dist/lib/long-task-evidence-capability-policy.js +80 -38
- package/dist/lib/long-task-evidence-capability-runtime.js +39 -0
- package/dist/lib/long-task-evidence-capability-types.d.ts +14 -1
- package/dist/lib/long-task-evidence-findings.js +3 -0
- package/dist/lib/long-task-evidence-sensitivity-policy.js +38 -0
- package/dist/lib/long-task-evidence-v2.js +7 -1
- package/dist/lib/long-task-final-integrity.d.ts +16 -0
- package/dist/lib/long-task-final-integrity.js +98 -0
- package/dist/lib/long-task-final-v2.js +17 -34
- package/dist/lib/long-task-outcome-parser.js +22 -4
- package/dist/lib/long-task-playwright-case-evidence.d.ts +2 -0
- package/dist/lib/long-task-playwright-case-evidence.js +10 -2
- package/dist/lib/long-task-playwright-evidence.d.ts +1 -0
- package/dist/lib/long-task-playwright-evidence.js +33 -0
- package/dist/lib/long-task-product-shape.d.ts +3 -1
- package/dist/lib/long-task-product-shape.js +100 -4
- package/dist/lib/long-task-requirement-shape.js +3 -0
- package/dist/lib/long-task-root-shape.js +12 -6
- package/dist/lib/long-task-runner-freeze.js +16 -0
- package/dist/lib/long-task-runtime-types.d.ts +11 -2
- package/dist/lib/long-task-semantic-assurance-policy.d.ts +4 -0
- package/dist/lib/long-task-semantic-assurance-policy.js +52 -0
- package/dist/lib/long-task-semantic-contract-types.d.ts +18 -1
- package/dist/lib/long-task-semantic-drift-migration.js +33 -2
- package/dist/lib/long-task-semantic-mutation.d.ts +7 -0
- package/dist/lib/long-task-semantic-mutation.js +81 -0
- package/dist/lib/long-task-shape-primitives.d.ts +1 -1
- package/dist/lib/long-task-shape-primitives.js +1 -0
- package/dist/lib/long-task-source-authority-types.d.ts +2 -0
- package/dist/lib/long-task-source-item-parser.d.ts +1 -1
- package/dist/lib/long-task-source-item-parser.js +150 -104
- package/dist/lib/long-task-source-markers.d.ts +12 -0
- package/dist/lib/long-task-source-markers.js +146 -0
- package/dist/lib/long-task-source-target-continuity.d.ts +1 -1
- package/dist/lib/long-task-source-target-continuity.js +80 -55
- package/dist/lib/long-task-source-target-index.js +7 -29
- package/dist/lib/long-task-status-v2.d.ts +1 -0
- package/dist/lib/long-task-status-v2.js +2 -2
- package/dist/lib/long-task-target-policy.js +20 -0
- package/dist/lib/long-task-ui-design-policy.js +34 -1
- package/dist/lib/long-task-ui-surface-shape.js +33 -2
- package/dist/lib/long-task-ui-surface-types.d.ts +8 -0
- package/dist/lib/long-task-verification-preview.d.ts +10 -0
- package/dist/lib/long-task-verifier-dependency-closure.d.ts +3 -0
- package/dist/lib/long-task-verifier-dependency-closure.js +179 -0
- package/dist/lib/long-task-verifier-v2.js +12 -2
- package/dist/lib/long-task-workspace.js +5 -1
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +101 -25
- package/package.json +2 -2
|
@@ -5,6 +5,16 @@ export type CounterfactualMutationV2 = {
|
|
|
5
5
|
type: "replace_file";
|
|
6
6
|
path: string;
|
|
7
7
|
fixture_path: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: "replace_json_value";
|
|
10
|
+
path: string;
|
|
11
|
+
pointer: string;
|
|
12
|
+
value: unknown;
|
|
13
|
+
} | {
|
|
14
|
+
type: "replace_text";
|
|
15
|
+
path: string;
|
|
16
|
+
match: string;
|
|
17
|
+
replacement: string;
|
|
8
18
|
};
|
|
9
19
|
export interface CounterfactualControlV2 {
|
|
10
20
|
key: string;
|
|
@@ -13,6 +23,7 @@ export interface CounterfactualControlV2 {
|
|
|
13
23
|
check_key: string;
|
|
14
24
|
mutation: CounterfactualMutationV2;
|
|
15
25
|
expected_assertion_failures: string[];
|
|
26
|
+
preserved_assertions: string[];
|
|
16
27
|
}
|
|
17
28
|
export interface GlobalCounterfactualControlV2 {
|
|
18
29
|
key: string;
|
|
@@ -21,4 +32,5 @@ export interface GlobalCounterfactualControlV2 {
|
|
|
21
32
|
check_key: string;
|
|
22
33
|
mutation: CounterfactualMutationV2;
|
|
23
34
|
expected_assertion_failures: string[];
|
|
35
|
+
preserved_assertions: string[];
|
|
24
36
|
}
|
|
@@ -134,6 +134,7 @@ export async function compileDeliveryContract(workdirInput, projectRootInput = p
|
|
|
134
134
|
source_claims: contract.source_claims,
|
|
135
135
|
stages: contract.stages,
|
|
136
136
|
global: {
|
|
137
|
+
applicability: contract.global.applicability,
|
|
137
138
|
product: contract.global.product,
|
|
138
139
|
technical: contract.global.technical,
|
|
139
140
|
acceptance: {
|
|
@@ -4,6 +4,7 @@ import { assertRepositoryPattern, matchesRepoPattern, proveRepositoryPatternSubs
|
|
|
4
4
|
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
5
5
|
import { sha256Hex } from "./strict-codec.js";
|
|
6
6
|
import { repoRelative, resolveInsideRepository, } from "./long-task-workspace.js";
|
|
7
|
+
import { mutateSemanticText } from "./long-task-semantic-mutation.js";
|
|
7
8
|
export function validateVerificationInputSeparation(contract, checks, workdirRelative) {
|
|
8
9
|
const implementation = contract.outcomes.flatMap((outcome) => [
|
|
9
10
|
...outcome.technical.expected_change_paths,
|
|
@@ -133,12 +134,35 @@ async function validateScopeCounterfactualPaths(options) {
|
|
|
133
134
|
!(await stat(target).catch(() => null)))
|
|
134
135
|
throw new Error(`counterfactual_path_not_found:${options.scope}:${relative}`);
|
|
135
136
|
}
|
|
137
|
+
if (options.mutation.type === "replace_json_value" ||
|
|
138
|
+
options.mutation.type === "replace_text") {
|
|
139
|
+
const replacementTarget = resolveInsideRepository(options.repository, options.mutation.path, `${options.scope}.counterfactual.path`);
|
|
140
|
+
if (!(await stat(replacementTarget).catch(() => null)))
|
|
141
|
+
return;
|
|
142
|
+
try {
|
|
143
|
+
mutateSemanticText(await readFile(replacementTarget, "utf8"), options.mutation, false);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
147
|
+
throw new Error(`counterfactual_semantic_mutation_invalid:${options.scope}:${options.controlKey}:${message}`);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
136
151
|
if (options.mutation.type !== "replace_file")
|
|
137
152
|
return;
|
|
138
153
|
const fixtureTarget = resolveInsideRepository(options.repository, options.mutation.fixture_path, `${options.scope}.counterfactual.fixture`);
|
|
139
154
|
const fixture = repoRelative(options.repository, await assertProtectedRepositoryFile(options.repository, fixtureTarget, `${options.scope}.counterfactual.fixture`));
|
|
140
155
|
if (!Object.hasOwn(options.check.verification_input_hashes, fixture))
|
|
141
156
|
throw new Error(`counterfactual_fixture_must_be_verification_input:${options.scope}:${fixture}`);
|
|
157
|
+
const replacementTarget = resolveInsideRepository(options.repository, options.mutation.path, `${options.scope}.counterfactual.path`);
|
|
158
|
+
if (await stat(replacementTarget).catch(() => null)) {
|
|
159
|
+
const [fixtureBytes, targetBytes] = await Promise.all([
|
|
160
|
+
readFile(fixtureTarget),
|
|
161
|
+
readFile(replacementTarget),
|
|
162
|
+
]);
|
|
163
|
+
if (fixtureBytes.equals(targetBytes))
|
|
164
|
+
throw new Error(`counterfactual_replacement_must_change_carrier:${options.scope}:${options.controlKey}`);
|
|
165
|
+
}
|
|
142
166
|
}
|
|
143
167
|
export async function hashDeclaredFiles(repository, files, label) {
|
|
144
168
|
const result = {};
|
|
@@ -8,9 +8,12 @@ import { validateEvidenceCapabilityDeclarations } from "./long-task-evidence-cap
|
|
|
8
8
|
import { validateDeliveryStages } from "./long-task-stage-policy.js";
|
|
9
9
|
import { validateExecutionTargets, validateExternalConfirmationImpacts, } from "./long-task-target-policy.js";
|
|
10
10
|
import { validateUiSurfaceBindings } from "./long-task-ui-surface-policy.js";
|
|
11
|
+
import { controlFieldFacts } from "./long-task-control-fields.js";
|
|
12
|
+
import { validateSemanticAssuranceShape } from "./long-task-semantic-assurance-policy.js";
|
|
11
13
|
export function validateDeliveryContractStructure(contract) {
|
|
12
14
|
validateUniqueKeys(contract);
|
|
13
15
|
validateDependencies(contract);
|
|
16
|
+
validateControlClosure(contract);
|
|
14
17
|
validateOwnerAndBindings(contract);
|
|
15
18
|
validateDeclaredCheckSafety(contract);
|
|
16
19
|
validateEvidenceAdapters(contract);
|
|
@@ -22,6 +25,7 @@ export function validateDeliveryContractStructure(contract) {
|
|
|
22
25
|
assertCompiledClaimsCovered(claims);
|
|
23
26
|
validateDeliveryStages(contract);
|
|
24
27
|
validateExecutionTargets(contract);
|
|
28
|
+
validateSemanticAssuranceShape(contract);
|
|
25
29
|
validateEvidenceCapabilityDeclarations(contract);
|
|
26
30
|
validateExternalConfirmationImpacts(contract, claims);
|
|
27
31
|
}
|
|
@@ -30,8 +34,10 @@ export function deliveryContractStructureDiagnostics(contract) {
|
|
|
30
34
|
const report = (message) => diagnostics.push(message);
|
|
31
35
|
validateUniqueKeys(contract, report);
|
|
32
36
|
validateDependencies(contract, report);
|
|
37
|
+
validateControlClosure(contract, report);
|
|
33
38
|
validateDeliveryStages(contract, report);
|
|
34
39
|
validateExecutionTargets(contract, report);
|
|
40
|
+
validateSemanticAssuranceShape(contract, report);
|
|
35
41
|
validateEvidenceCapabilityDeclarations(contract, report);
|
|
36
42
|
validateOwnerAndBindings(contract, report);
|
|
37
43
|
validateDeclaredCheckSafety(contract, report);
|
|
@@ -73,6 +79,7 @@ function validateUniqueKeys(contract, report) {
|
|
|
73
79
|
unique(outcome.acceptance.checks.map((check) => check.key), `check_key_duplicate:${outcome.key}`, report);
|
|
74
80
|
unique(outcome.product.requirements.map((item) => item.key), `requirement_key_duplicate:${outcome.key}`, report);
|
|
75
81
|
unique(outcome.product.controls.map((control) => control.key), `control_key_duplicate:${outcome.key}`, report);
|
|
82
|
+
unique(outcome.product.control_relations.map((relation) => relation.key), `control_relation_key_duplicate:${outcome.key}`, report);
|
|
76
83
|
unique(outcome.product.non_completing_outcomes.map((item) => item.key), `non_completing_key_duplicate:${outcome.key}`, report);
|
|
77
84
|
unique(outcome.technical.obligations.map((item) => item.key), `obligation_key_duplicate:${outcome.key}`, report);
|
|
78
85
|
unique(outcome.technical.forbidden_shortcuts.map((item) => item.key), `forbidden_shortcut_key_duplicate:${outcome.key}`, report);
|
|
@@ -87,6 +94,45 @@ function validateUniqueKeys(contract, report) {
|
|
|
87
94
|
for (const check of contract.global.acceptance.checks)
|
|
88
95
|
unique([...check.positive_assertions, ...check.negative_assertions].map((assertion) => assertion.observation), `assertion_observation_duplicate:GLOBAL:${check.key}`, report);
|
|
89
96
|
}
|
|
97
|
+
function validateControlClosure(contract, report) {
|
|
98
|
+
for (const outcome of contract.outcomes) {
|
|
99
|
+
const controls = new Set(outcome.product.controls.map((control) => control.key));
|
|
100
|
+
const closure = outcome.product.control_relation_closure;
|
|
101
|
+
const relations = outcome.product.control_relations;
|
|
102
|
+
if (closure.state === "unresolved")
|
|
103
|
+
issue(report, "control_relation_closure_unresolved", outcome.key);
|
|
104
|
+
if (closure.state === "specified" && !relations.length)
|
|
105
|
+
issue(report, "control_relation_required", outcome.key);
|
|
106
|
+
if (closure.state === "not_applicable" && relations.length)
|
|
107
|
+
issue(report, "control_relation_forbidden_when_not_applicable", outcome.key);
|
|
108
|
+
if (!controls.size && closure.state !== "not_applicable")
|
|
109
|
+
issue(report, "control_relation_closure_without_controls", outcome.key);
|
|
110
|
+
for (const control of outcome.product.controls) {
|
|
111
|
+
const facts = controlFieldFacts(control);
|
|
112
|
+
const unresolved = facts
|
|
113
|
+
.filter((fact) => fact.state === "unresolved")
|
|
114
|
+
.map((fact) => fact.contract_field);
|
|
115
|
+
if (unresolved.length)
|
|
116
|
+
issue(report, "control_field_unresolved", `${outcome.key}:${control.key}:${unresolved.join(",")}`);
|
|
117
|
+
if (!facts.some((fact) => [
|
|
118
|
+
"navigation_result",
|
|
119
|
+
"interaction",
|
|
120
|
+
"trigger",
|
|
121
|
+
"location",
|
|
122
|
+
].includes(fact.contract_field) && fact.state === "specified"))
|
|
123
|
+
issue(report, "control_root_behavior_required", `${outcome.key}:${control.key}`);
|
|
124
|
+
}
|
|
125
|
+
for (const relation of relations) {
|
|
126
|
+
if (relation.control_refs.length < 2)
|
|
127
|
+
issue(report, "control_relation_control_refs_required", `${outcome.key}:${relation.key}`);
|
|
128
|
+
if (new Set(relation.control_refs).size !== relation.control_refs.length)
|
|
129
|
+
issue(report, "control_relation_control_ref_duplicate", `${outcome.key}:${relation.key}`);
|
|
130
|
+
for (const reference of relation.control_refs)
|
|
131
|
+
if (!controls.has(reference))
|
|
132
|
+
issue(report, "control_relation_control_ref_unknown", `${outcome.key}:${relation.key}:${reference}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
90
136
|
function validateOwnerAndBindings(contract, report) {
|
|
91
137
|
const contextRefs = new Set(contract.task.context_refs);
|
|
92
138
|
for (const outcome of contract.outcomes) {
|
|
@@ -18,6 +18,7 @@ export async function validateLongTaskDesignResourceHandoffs(contract, repositor
|
|
|
18
18
|
invalid("target_handoff_missing", contractTarget.target.key);
|
|
19
19
|
consumed.add(contractTarget.target.key);
|
|
20
20
|
validateTargetIdentity(contractTarget, indexedTarget);
|
|
21
|
+
validateTargetCapabilities(contract, contractTarget, indexedTarget);
|
|
21
22
|
validateCoverageClaims(contract, contractTarget, indexedTarget);
|
|
22
23
|
validateBlockerBindings(contract, contractTarget, indexedTarget);
|
|
23
24
|
}
|
|
@@ -62,21 +63,20 @@ function validateCoverageClaims(contract, contractTarget, indexed) {
|
|
|
62
63
|
const check = contract.outcomes
|
|
63
64
|
.find((item) => item.key === contractTarget.outcome_key)
|
|
64
65
|
.acceptance.checks.find((item) => item.key === target.conformance_check_ref);
|
|
65
|
-
const assertion = check.positive_assertions.find((item) => item.key === target.conformance_assertion_ref);
|
|
66
66
|
const claims = new Map(contract.source_claims.map((item) => [item.key, item]));
|
|
67
67
|
const rows = indexed.preflight.handoff.coverage.filter((row) => row.disposition === "covered" && row.target_refs.includes(target.key));
|
|
68
68
|
if (!rows.length)
|
|
69
69
|
invalid("target_covered_claims_required", target.key);
|
|
70
|
+
const facts = indexed.preflight.handoff.facts.filter((fact) => fact.target_ref === target.key);
|
|
71
|
+
if (!facts.length)
|
|
72
|
+
invalid("target_facts_required", target.key);
|
|
70
73
|
const claimsBySourceItem = new Map();
|
|
71
74
|
for (const row of rows)
|
|
72
75
|
for (const sourceItemRef of row.source_item_refs) {
|
|
73
76
|
const localClaims = designSourceItemClaims(contract, contractTarget, indexed, sourceItemRef, claims);
|
|
74
77
|
claimsBySourceItem.set(sourceItemRef, localClaims);
|
|
75
|
-
for (const localClaimRef of localClaims)
|
|
76
|
-
if (!assertion.claims.includes(localClaimRef))
|
|
77
|
-
invalid("coverage_claim_not_in_conformance_assertion", `${target.key}:${sourceItemRef}:${localClaimRef}`);
|
|
78
78
|
}
|
|
79
|
-
validateVerificationMethodBindings(target, check,
|
|
79
|
+
validateVerificationMethodBindings(target, check, facts, claimsBySourceItem);
|
|
80
80
|
}
|
|
81
81
|
function validateBlockerBindings(contract, contractTarget, indexed) {
|
|
82
82
|
const bound = new Map(contractTarget.binding.acceptance_blockers.map((item) => [item.key, item]));
|
|
@@ -94,6 +94,7 @@ function validateBlockerBindings(contract, contractTarget, indexed) {
|
|
|
94
94
|
invalid("acceptance_blocker_unbound", `${contractTarget.target.key}:${blocker.key}`);
|
|
95
95
|
assertSameSet(contractBlocker.source_item_refs, blocker.source_item_refs, "acceptance_blocker_source_items_mismatch", blocker.key);
|
|
96
96
|
assertSameSet(contractBlocker.verification_methods, blocker.verification_methods, "acceptance_blocker_methods_mismatch", blocker.key);
|
|
97
|
+
assertSameSet(contractBlocker.required_capabilities, blocker.required_capabilities, "acceptance_blocker_capabilities_mismatch", blocker.key);
|
|
97
98
|
for (const method of blocker.verification_methods)
|
|
98
99
|
if (!availableMethods.has(method))
|
|
99
100
|
invalid("acceptance_blocker_method_unbound", `${blocker.key}:${method}`);
|
|
@@ -102,6 +103,12 @@ function validateBlockerBindings(contract, contractTarget, indexed) {
|
|
|
102
103
|
return local.map((claimRef) => `${contractTarget.outcome_key}.${claimRef}`);
|
|
103
104
|
});
|
|
104
105
|
if (contractBlocker.status === "machine_claim") {
|
|
106
|
+
const executionTarget = contract.task.execution_targets.find((item) => item.key === contractTarget.binding.target_ref);
|
|
107
|
+
if (!executionTarget)
|
|
108
|
+
invalid("execution_target_unknown", `${contractTarget.target.key}:${contractTarget.binding.target_ref}`);
|
|
109
|
+
for (const capability of blocker.required_capabilities)
|
|
110
|
+
if (!executionTarget.capabilities.includes(capability))
|
|
111
|
+
invalid("acceptance_blocker_target_capability_missing", `${blocker.key}:${executionTarget.key}:${capability}`);
|
|
105
112
|
const expectedLocal = fullClaimRefs.map((claimRef) => claimRef.slice(contractTarget.outcome_key.length + 1));
|
|
106
113
|
for (const claimRef of expectedLocal)
|
|
107
114
|
if (!contractBlocker.refs.includes(claimRef))
|
|
@@ -133,8 +140,8 @@ function designSourceItemClaims(contract, contractTarget, indexed, sourceItemRef
|
|
|
133
140
|
return claimRef.slice(prefix.length);
|
|
134
141
|
});
|
|
135
142
|
}
|
|
136
|
-
function validateVerificationMethodBindings(target, check,
|
|
137
|
-
const expectedMethods = new Set(
|
|
143
|
+
function validateVerificationMethodBindings(target, check, facts, claimsBySourceItem) {
|
|
144
|
+
const expectedMethods = new Set(facts.map((fact) => fact.verification_method));
|
|
138
145
|
const bindings = target.verification_method_bindings;
|
|
139
146
|
assertSameSet(bindings.map((item) => item.method), [...expectedMethods], "verification_methods_mismatch", target.key);
|
|
140
147
|
const assertionRefs = bindings.map((item) => item.assertion_ref);
|
|
@@ -142,13 +149,14 @@ function validateVerificationMethodBindings(target, check, rows, claimsBySourceI
|
|
|
142
149
|
invalid("verification_method_assertion_duplicate", target.key);
|
|
143
150
|
if (assertionRefs.includes(target.conformance_assertion_ref))
|
|
144
151
|
invalid("verification_method_assertion_must_be_independent", target.key);
|
|
152
|
+
const boundFactRefs = [];
|
|
145
153
|
for (const binding of bindings) {
|
|
146
154
|
const assertion = check.positive_assertions.find((item) => item.key === binding.assertion_ref);
|
|
147
155
|
if (!assertion)
|
|
148
156
|
invalid("verification_method_assertion_unknown", `${target.key}:${binding.method}:${binding.assertion_ref}`);
|
|
149
|
-
const sourceItems = new Set(
|
|
150
|
-
.filter((
|
|
151
|
-
.flatMap((
|
|
157
|
+
const sourceItems = new Set(facts
|
|
158
|
+
.filter((fact) => fact.verification_method === binding.method)
|
|
159
|
+
.flatMap((fact) => fact.source_item_refs));
|
|
152
160
|
for (const sourceItemRef of sourceItems)
|
|
153
161
|
for (const claimRef of claimsBySourceItem.get(sourceItemRef) ?? [])
|
|
154
162
|
if (!assertion.claims.includes(claimRef))
|
|
@@ -156,14 +164,60 @@ function validateVerificationMethodBindings(target, check, rows, claimsBySourceI
|
|
|
156
164
|
for (const capability of requiredCapabilities(binding.method))
|
|
157
165
|
if (!assertion.evidence_capabilities.includes(capability))
|
|
158
166
|
invalid("verification_method_capability_required", `${target.key}:${binding.method}:${capability}`);
|
|
167
|
+
assertSameSet(binding.evidence_artifacts.map((item) => item.condition_key), target.condition_keys, "verification_method_evidence_conditions_mismatch", `${target.key}:${binding.method}`);
|
|
168
|
+
for (const artifact of binding.evidence_artifacts) {
|
|
169
|
+
const expectedFactRefs = facts
|
|
170
|
+
.filter((fact) => fact.verification_method === binding.method &&
|
|
171
|
+
fact.condition_ref === artifact.condition_key)
|
|
172
|
+
.map((fact) => fact.key);
|
|
173
|
+
assertSameSet(artifact.fact_refs, expectedFactRefs, "design_method_fact_refs_mismatch", `${target.key}:${binding.method}:${artifact.condition_key}`);
|
|
174
|
+
boundFactRefs.push(...artifact.fact_refs);
|
|
175
|
+
}
|
|
159
176
|
}
|
|
177
|
+
assertSameSet(boundFactRefs, facts.map((fact) => fact.key), "design_method_fact_refs_mismatch", target.key);
|
|
160
178
|
}
|
|
161
179
|
function requiredCapabilities(method) {
|
|
162
180
|
if (method === "interaction_trace")
|
|
163
|
-
return ["interaction_trace", "target_runtime"];
|
|
181
|
+
return ["design_method", "interaction_trace", "target_runtime"];
|
|
164
182
|
if (method === "component_state")
|
|
165
|
-
return [
|
|
166
|
-
|
|
183
|
+
return [
|
|
184
|
+
"design_method",
|
|
185
|
+
"design_conformance",
|
|
186
|
+
"interaction_trace",
|
|
187
|
+
"target_runtime",
|
|
188
|
+
];
|
|
189
|
+
return ["design_method", "design_conformance", "target_runtime"];
|
|
190
|
+
}
|
|
191
|
+
function validateTargetCapabilities(contract, contractTarget, indexed) {
|
|
192
|
+
const executionTarget = contract.task.execution_targets.find((item) => item.key === contractTarget.binding.target_ref);
|
|
193
|
+
if (!executionTarget)
|
|
194
|
+
invalid("execution_target_unknown", `${contractTarget.target.key}:${contractTarget.binding.target_ref}`);
|
|
195
|
+
const required = new Set();
|
|
196
|
+
for (const method of contractTarget.target.verification_method_bindings.map((item) => item.method)) {
|
|
197
|
+
if (method === "responsive_reflow")
|
|
198
|
+
required.add("viewport-control");
|
|
199
|
+
if (method === "motion_timeline")
|
|
200
|
+
required.add("motion-observation");
|
|
201
|
+
if (method === "accessibility_semantics")
|
|
202
|
+
required.add("assistive-technology");
|
|
203
|
+
}
|
|
204
|
+
for (const conditionRef of indexed.target.condition_refs) {
|
|
205
|
+
const condition = indexed.preflight.handoff.conditions.find((item) => item.key === conditionRef);
|
|
206
|
+
const input = condition.input_methods[0].toLowerCase();
|
|
207
|
+
if (["mouse", "pointer", "trackpad"].includes(input))
|
|
208
|
+
required.add("pointer-input");
|
|
209
|
+
if (input === "keyboard")
|
|
210
|
+
required.add("keyboard-input");
|
|
211
|
+
if (["touch", "pen", "stylus"].includes(input))
|
|
212
|
+
required.add("touch-input");
|
|
213
|
+
if (["screen-reader", "voice-control", "switch-control"].includes(input))
|
|
214
|
+
required.add("assistive-technology");
|
|
215
|
+
if (condition.motion === "reduced")
|
|
216
|
+
required.add("reduced-motion");
|
|
217
|
+
}
|
|
218
|
+
for (const capability of required)
|
|
219
|
+
if (!executionTarget.capabilities.includes(capability))
|
|
220
|
+
invalid("execution_target_capability_missing", `${contractTarget.target.key}:${executionTarget.key}:${capability}`);
|
|
167
221
|
}
|
|
168
222
|
function assertSameSet(actual, expected, code, detail) {
|
|
169
223
|
const left = [...new Set(actual)].sort();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DESIGN_RESOURCE_VERIFICATION_METHODS } from "./design-resource-handoff-types.js";
|
|
1
2
|
export function decodeEvidenceCapabilityRecords(value) {
|
|
2
3
|
if (!Array.isArray(value))
|
|
3
4
|
throw invalidRecord("must_be_array");
|
|
@@ -179,6 +180,38 @@ function decodeRecord(value, index) {
|
|
|
179
180
|
session_id: nonEmpty(row.session_id, `${label}.session_id`),
|
|
180
181
|
cold_start: row.cold_start,
|
|
181
182
|
};
|
|
183
|
+
case "design_method":
|
|
184
|
+
exact(row, label, [
|
|
185
|
+
"assertion_key",
|
|
186
|
+
"capability",
|
|
187
|
+
"design_target_ref",
|
|
188
|
+
"target_ref",
|
|
189
|
+
"method",
|
|
190
|
+
"cells",
|
|
191
|
+
]);
|
|
192
|
+
return {
|
|
193
|
+
...base,
|
|
194
|
+
capability,
|
|
195
|
+
design_target_ref: key(row.design_target_ref, `${label}.design_target_ref`),
|
|
196
|
+
target_ref: key(row.target_ref, `${label}.target_ref`),
|
|
197
|
+
method: literal(row.method, DESIGN_RESOURCE_VERIFICATION_METHODS, `${label}.method`),
|
|
198
|
+
cells: array(row.cells, `${label}.cells`).map((item, cellIndex) => {
|
|
199
|
+
const cellLabel = `${label}.cells[${cellIndex}]`;
|
|
200
|
+
const cell = record(item, cellLabel);
|
|
201
|
+
exact(cell, cellLabel, [
|
|
202
|
+
"condition_key",
|
|
203
|
+
"artifact_path",
|
|
204
|
+
"observation_artifact_path",
|
|
205
|
+
"fact_refs",
|
|
206
|
+
]);
|
|
207
|
+
return {
|
|
208
|
+
condition_key: key(cell.condition_key, `${cellLabel}.condition_key`),
|
|
209
|
+
artifact_path: nonEmpty(cell.artifact_path, `${cellLabel}.artifact_path`),
|
|
210
|
+
observation_artifact_path: nonEmpty(cell.observation_artifact_path, `${cellLabel}.observation_artifact_path`),
|
|
211
|
+
fact_refs: designFactRefs(cell.fact_refs, `${cellLabel}.fact_refs`),
|
|
212
|
+
};
|
|
213
|
+
}),
|
|
214
|
+
};
|
|
182
215
|
case "input_variation":
|
|
183
216
|
exact(row, label, [
|
|
184
217
|
"assertion_key",
|
|
@@ -242,9 +275,23 @@ function strings(value, label) {
|
|
|
242
275
|
function keys(value, label) {
|
|
243
276
|
return array(value, label).map((item, index) => key(item, `${label}[${index}]`));
|
|
244
277
|
}
|
|
278
|
+
function designFactRefs(value, label) {
|
|
279
|
+
return array(value, label).map((item, index) => {
|
|
280
|
+
const result = nonEmpty(item, `${label}[${index}]`);
|
|
281
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/u.test(result))
|
|
282
|
+
throw invalidRecord(`${label}[${index}]`);
|
|
283
|
+
return result;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
245
286
|
function sha(value, label) {
|
|
246
287
|
const result = nonEmpty(value, label);
|
|
247
288
|
if (!/^[a-f0-9]{64}$/u.test(result))
|
|
248
289
|
throw invalidRecord(label);
|
|
249
290
|
return result;
|
|
250
291
|
}
|
|
292
|
+
function literal(value, allowed, label) {
|
|
293
|
+
const result = nonEmpty(value, label);
|
|
294
|
+
if (!allowed.includes(result))
|
|
295
|
+
throw invalidRecord(label);
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
@@ -4,47 +4,56 @@ export { decodeEvidenceCapabilityRecords } from "./long-task-evidence-capability
|
|
|
4
4
|
export function validateEvidenceCapabilityDeclarations(contract, report) {
|
|
5
5
|
const targets = new Map(contract.task.execution_targets.map((target) => [target.key, target]));
|
|
6
6
|
for (const [outcomeKey, check] of allChecks(contract)) {
|
|
7
|
-
|
|
8
|
-
if (!check.journey_roles.length)
|
|
9
|
-
issue(report, "journey_role_required", checkLabel(outcomeKey, check.key));
|
|
10
|
-
validateScenario(check, outcomeKey, report);
|
|
11
|
-
for (const assertion of [
|
|
12
|
-
...check.positive_assertions,
|
|
13
|
-
...check.negative_assertions,
|
|
14
|
-
]) {
|
|
15
|
-
const label = `${checkLabel(outcomeKey, check.key)}:${assertion.key}`;
|
|
16
|
-
unique(assertion.evidence_capabilities, "evidence_capability_duplicate", label, report);
|
|
17
|
-
if (!assertion.evidence_capabilities.length)
|
|
18
|
-
issue(report, "evidence_capability_required", label);
|
|
19
|
-
if (assertion.claims.length &&
|
|
20
|
-
check.proof_surface !== "implementation_structure" &&
|
|
21
|
-
assertion.evidence_capabilities.every((capability) => capability === "presence"))
|
|
22
|
-
issue(report, "presence_cannot_prove_behavior", label);
|
|
23
|
-
if (assertion.operator === "exists" &&
|
|
24
|
-
!assertion.evidence_capabilities.includes("presence"))
|
|
25
|
-
issue(report, "exists_requires_presence_capability", label);
|
|
26
|
-
if (assertion.evidence_capabilities.includes("visual_render") &&
|
|
27
|
-
!check.artifact_globs.length)
|
|
28
|
-
issue(report, "visual_render_artifact_required", label);
|
|
29
|
-
if (assertion.evidence_capabilities.includes("design_conformance") &&
|
|
30
|
-
!check.artifact_globs.length)
|
|
31
|
-
issue(report, "design_conformance_artifact_required", label);
|
|
32
|
-
if (assertion.evidence_capabilities.includes("interaction_trace") &&
|
|
33
|
-
!check.scenario.when.length)
|
|
34
|
-
issue(report, "interaction_trace_actions_required", label);
|
|
35
|
-
if (check.runner.type === "playwright_test" &&
|
|
36
|
-
assertion.evidence_capabilities.some((capability) => capability !== "presence" &&
|
|
37
|
-
capability !== "interaction_trace" &&
|
|
38
|
-
capability !== "design_conformance" &&
|
|
39
|
-
capability !== "target_runtime"))
|
|
40
|
-
issue(report, "playwright_evidence_capability_unsupported", label);
|
|
41
|
-
if (["boundary_invocation", "external_side_effect"].some((capability) => assertion.evidence_capabilities.includes(capability)) &&
|
|
42
|
-
targets.get(check.execution_target.target_ref)?.role !== "observer")
|
|
43
|
-
issue(report, "observer_check_target_required", label);
|
|
44
|
-
}
|
|
7
|
+
validateCheckEvidenceCapabilityDeclarations(check, outcomeKey, targets, report);
|
|
45
8
|
}
|
|
46
9
|
validateJourneySeparation(contract, report);
|
|
47
10
|
}
|
|
11
|
+
function validateCheckEvidenceCapabilityDeclarations(check, outcomeKey, targets, report) {
|
|
12
|
+
const label = checkLabel(outcomeKey, check.key);
|
|
13
|
+
unique(check.journey_roles, "journey_role_duplicate", label, report);
|
|
14
|
+
if (!check.journey_roles.length)
|
|
15
|
+
issue(report, "journey_role_required", label);
|
|
16
|
+
validateScenario(check, outcomeKey, report);
|
|
17
|
+
for (const assertion of [
|
|
18
|
+
...check.positive_assertions,
|
|
19
|
+
...check.negative_assertions,
|
|
20
|
+
])
|
|
21
|
+
validateAssertionEvidenceCapabilityDeclarations(assertion, check, targets, `${label}:${assertion.key}`, report);
|
|
22
|
+
}
|
|
23
|
+
function validateAssertionEvidenceCapabilityDeclarations(assertion, check, targets, label, report) {
|
|
24
|
+
unique(assertion.evidence_capabilities, "evidence_capability_duplicate", label, report);
|
|
25
|
+
if (!assertion.evidence_capabilities.length)
|
|
26
|
+
issue(report, "evidence_capability_required", label);
|
|
27
|
+
if (assertion.claims.length &&
|
|
28
|
+
check.proof_surface !== "implementation_structure" &&
|
|
29
|
+
assertion.evidence_capabilities.every((capability) => capability === "presence"))
|
|
30
|
+
issue(report, "presence_cannot_prove_behavior", label);
|
|
31
|
+
if (assertion.operator === "exists" &&
|
|
32
|
+
!assertion.evidence_capabilities.includes("presence"))
|
|
33
|
+
issue(report, "exists_requires_presence_capability", label);
|
|
34
|
+
if (assertion.evidence_capabilities.includes("visual_render") &&
|
|
35
|
+
!check.artifact_globs.length)
|
|
36
|
+
issue(report, "visual_render_artifact_required", label);
|
|
37
|
+
if (assertion.evidence_capabilities.includes("design_conformance") &&
|
|
38
|
+
!check.artifact_globs.length)
|
|
39
|
+
issue(report, "design_conformance_artifact_required", label);
|
|
40
|
+
if (assertion.evidence_capabilities.includes("design_method") &&
|
|
41
|
+
!check.artifact_globs.length)
|
|
42
|
+
issue(report, "design_method_artifact_required", label);
|
|
43
|
+
if (assertion.evidence_capabilities.includes("interaction_trace") &&
|
|
44
|
+
!check.scenario.when.length)
|
|
45
|
+
issue(report, "interaction_trace_actions_required", label);
|
|
46
|
+
if (check.runner.type === "playwright_test" &&
|
|
47
|
+
assertion.evidence_capabilities.some((capability) => capability !== "presence" &&
|
|
48
|
+
capability !== "interaction_trace" &&
|
|
49
|
+
capability !== "design_conformance" &&
|
|
50
|
+
capability !== "design_method" &&
|
|
51
|
+
capability !== "target_runtime"))
|
|
52
|
+
issue(report, "playwright_evidence_capability_unsupported", label);
|
|
53
|
+
if (["boundary_invocation", "external_side_effect"].some((capability) => assertion.evidence_capabilities.includes(capability)) &&
|
|
54
|
+
targets.get(check.execution_target.target_ref)?.role !== "observer")
|
|
55
|
+
issue(report, "observer_check_target_required", label);
|
|
56
|
+
}
|
|
48
57
|
function validateScenario(check, outcomeKey, report) {
|
|
49
58
|
const label = checkLabel(outcomeKey, check.key);
|
|
50
59
|
if (!check.scenario.given.length)
|
|
@@ -127,8 +136,41 @@ export function evaluateEvidenceCapabilities(check, records, artifactHashes) {
|
|
|
127
136
|
}
|
|
128
137
|
complete[assertion.key] = assertionComplete;
|
|
129
138
|
}
|
|
139
|
+
validateDistinctDesignMethodArtifacts(check, runtimeRecords, artifactHashes, findings);
|
|
130
140
|
return { complete, findings };
|
|
131
141
|
}
|
|
142
|
+
function validateDistinctDesignMethodArtifacts(check, records, artifactHashes, findings) {
|
|
143
|
+
const pathOwners = new Map();
|
|
144
|
+
const digestOwners = new Map();
|
|
145
|
+
for (const record of records) {
|
|
146
|
+
if (record.capability !== "design_method")
|
|
147
|
+
continue;
|
|
148
|
+
for (const cell of record.cells) {
|
|
149
|
+
const currentOwner = `${record.method}:${cell.condition_key}`;
|
|
150
|
+
const pathOwner = pathOwners.get(cell.observation_artifact_path);
|
|
151
|
+
if (pathOwner)
|
|
152
|
+
findings.push(reusedDesignMethodArtifactFinding(check, record.assertion_key, currentOwner, pathOwner, "path", cell.observation_artifact_path));
|
|
153
|
+
else
|
|
154
|
+
pathOwners.set(cell.observation_artifact_path, currentOwner);
|
|
155
|
+
const digest = artifactHashes[cell.observation_artifact_path];
|
|
156
|
+
if (!digest)
|
|
157
|
+
continue;
|
|
158
|
+
const digestOwner = digestOwners.get(digest);
|
|
159
|
+
if (digestOwner)
|
|
160
|
+
findings.push(reusedDesignMethodArtifactFinding(check, record.assertion_key, currentOwner, digestOwner, "sha256", digest));
|
|
161
|
+
else
|
|
162
|
+
digestOwners.set(digest, currentOwner);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function reusedDesignMethodArtifactFinding(check, assertionKey, currentOwner, previousOwner, identityKind, identity) {
|
|
167
|
+
return {
|
|
168
|
+
...checkFinding(check, "design_method_evidence_reused", `Design-method evidence ${identityKind} ${identity} is reused by ${previousOwner} and ${currentOwner}.`, "Emit method-and-condition evidence whose path and current content digest are both distinct for every verification-method cell."),
|
|
169
|
+
assertion_key: assertionKey,
|
|
170
|
+
expected: "distinct_method_condition_artifact_path_and_content",
|
|
171
|
+
actual: { identity_kind: identityKind, identity },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
132
174
|
function allChecks(contract) {
|
|
133
175
|
return [
|
|
134
176
|
...contract.global.acceptance.checks.map((check) => [null, check]),
|
|
@@ -27,12 +27,51 @@ export function validateRuntimeEvidenceRecord(check, record, artifactHashes) {
|
|
|
27
27
|
: "artifact_hash_mismatch";
|
|
28
28
|
case "design_conformance":
|
|
29
29
|
return validateDesignConformance(check, record, artifactHashes);
|
|
30
|
+
case "design_method":
|
|
31
|
+
return validateDesignMethod(check, record, artifactHashes);
|
|
30
32
|
case "target_runtime":
|
|
31
33
|
return validateTargetRuntime(check, record);
|
|
32
34
|
case "input_variation":
|
|
33
35
|
return validateInputVariation(record);
|
|
34
36
|
}
|
|
35
37
|
}
|
|
38
|
+
function validateDesignMethod(check, record, artifactHashes) {
|
|
39
|
+
const target = (check.design_conformance_targets ?? []).find((item) => item.key === record.design_target_ref &&
|
|
40
|
+
item.verification_method_bindings.some((binding) => binding.assertion_ref === record.assertion_key &&
|
|
41
|
+
binding.method === record.method));
|
|
42
|
+
if (!target)
|
|
43
|
+
return "design_method_binding_unknown";
|
|
44
|
+
if (target.target_ref !== record.target_ref ||
|
|
45
|
+
target.target_ref !== check.execution_target.target_ref)
|
|
46
|
+
return "target_mismatch";
|
|
47
|
+
const binding = target.verification_method_bindings.find((item) => item.assertion_ref === record.assertion_key &&
|
|
48
|
+
item.method === record.method);
|
|
49
|
+
if (!same([...record.cells.map((item) => item.condition_key)].sort(), [...target.condition_keys].sort()))
|
|
50
|
+
return "design_method_conditions_mismatch";
|
|
51
|
+
const expected = new Map(binding.evidence_artifacts.map((item) => [
|
|
52
|
+
item.condition_key,
|
|
53
|
+
{
|
|
54
|
+
artifact_path: item.path,
|
|
55
|
+
observation_artifact_path: item.observation_path,
|
|
56
|
+
fact_refs: item.fact_refs,
|
|
57
|
+
},
|
|
58
|
+
]));
|
|
59
|
+
if (record.cells.length !== expected.size)
|
|
60
|
+
return "design_method_cell_count_mismatch";
|
|
61
|
+
for (const cell of record.cells) {
|
|
62
|
+
const expectedCell = expected.get(cell.condition_key);
|
|
63
|
+
if (expectedCell?.artifact_path !== cell.artifact_path ||
|
|
64
|
+
expectedCell?.observation_artifact_path !== cell.observation_artifact_path)
|
|
65
|
+
return "design_method_artifact_path_mismatch";
|
|
66
|
+
if (!same([...cell.fact_refs].sort(), [...(expectedCell?.fact_refs ?? [])].sort()))
|
|
67
|
+
return "design_method_fact_refs_mismatch";
|
|
68
|
+
if (!artifactHashes[cell.artifact_path])
|
|
69
|
+
return "design_method_artifact_missing";
|
|
70
|
+
if (!artifactHashes[cell.observation_artifact_path])
|
|
71
|
+
return "design_method_observation_artifact_missing";
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
36
75
|
function validateDesignConformance(check, record, artifactHashes) {
|
|
37
76
|
const target = (check.design_conformance_targets ?? []).find((item) => item.key === record.design_target_ref &&
|
|
38
77
|
designTargetUsesAssertion(item, record.assertion_key));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EvidenceCapabilityV2 } from "./long-task-semantic-contract-types.js";
|
|
2
|
+
import type { DesignResourceVerificationMethod } from "./design-resource-handoff-types.js";
|
|
2
3
|
interface EvidenceRecordBaseV2 {
|
|
3
4
|
assertion_key: string;
|
|
4
5
|
capability: EvidenceCapabilityV2;
|
|
@@ -70,6 +71,18 @@ export interface TargetRuntimeEvidenceV2 extends EvidenceRecordBaseV2 {
|
|
|
70
71
|
session_id: string;
|
|
71
72
|
cold_start: boolean;
|
|
72
73
|
}
|
|
74
|
+
export interface DesignMethodEvidenceV2 extends EvidenceRecordBaseV2 {
|
|
75
|
+
capability: "design_method";
|
|
76
|
+
design_target_ref: string;
|
|
77
|
+
target_ref: string;
|
|
78
|
+
method: DesignResourceVerificationMethod;
|
|
79
|
+
cells: Array<{
|
|
80
|
+
condition_key: string;
|
|
81
|
+
artifact_path: string;
|
|
82
|
+
observation_artifact_path: string;
|
|
83
|
+
fact_refs: string[];
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
73
86
|
export interface InputVariationEvidenceV2 extends EvidenceRecordBaseV2 {
|
|
74
87
|
capability: "input_variation";
|
|
75
88
|
cases: Array<{
|
|
@@ -78,5 +91,5 @@ export interface InputVariationEvidenceV2 extends EvidenceRecordBaseV2 {
|
|
|
78
91
|
}>;
|
|
79
92
|
failure_case_observed: boolean;
|
|
80
93
|
}
|
|
81
|
-
export type EvidenceCapabilityRecordV2 = InteractionTraceEvidenceV2 | StateDeltaEvidenceV2 | CrossSurfaceConsistencyEvidenceV2 | DurableReadbackEvidenceV2 | BoundaryInvocationEvidenceV2 | ExternalSideEffectEvidenceV2 | FailureInjectionEvidenceV2 | VisualRenderEvidenceV2 | DesignConformanceEvidenceV2 | TargetRuntimeEvidenceV2 | InputVariationEvidenceV2;
|
|
94
|
+
export type EvidenceCapabilityRecordV2 = InteractionTraceEvidenceV2 | StateDeltaEvidenceV2 | CrossSurfaceConsistencyEvidenceV2 | DurableReadbackEvidenceV2 | BoundaryInvocationEvidenceV2 | ExternalSideEffectEvidenceV2 | FailureInjectionEvidenceV2 | VisualRenderEvidenceV2 | DesignConformanceEvidenceV2 | DesignMethodEvidenceV2 | TargetRuntimeEvidenceV2 | InputVariationEvidenceV2;
|
|
82
95
|
export {};
|
|
@@ -18,6 +18,9 @@ export function evaluateAssertionResults(check, observations) {
|
|
|
18
18
|
polarity,
|
|
19
19
|
passed: evaluation.passed,
|
|
20
20
|
claims: assertion.claims,
|
|
21
|
+
...(assertion.applicability_ref
|
|
22
|
+
? { applicability_ref: assertion.applicability_ref }
|
|
23
|
+
: {}),
|
|
21
24
|
observation: assertion.observation,
|
|
22
25
|
evidence_capabilities: assertion.evidence_capabilities,
|
|
23
26
|
evidence_complete: false,
|