project-tiny-context-harness 0.8.4 → 0.8.6
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 +394 -363
- package/assets/README.md +570 -514
- package/assets/README.zh-CN.md +331 -300
- package/assets/agents/.gitkeep +1 -1
- package/assets/agents/AGENTS_CORE.md +45 -25
- package/assets/context_templates/architecture.md +26 -25
- package/assets/context_templates/area.md +32 -31
- package/assets/context_templates/context.toml +30 -24
- package/assets/context_templates/deployment.md +35 -35
- package/assets/context_templates/global.md +57 -57
- package/assets/context_templates/product-surface-contract.md +70 -70
- package/assets/context_templates/screen-contract.md +189 -189
- package/assets/context_templates/verification.md +31 -30
- package/assets/github/.gitkeep +1 -1
- package/assets/github/harness.yml +39 -39
- package/assets/make/.gitkeep +1 -1
- package/assets/make/ty-context.mk +48 -48
- package/assets/skills/context_development_engineer/SKILL.md +155 -122
- package/assets/skills/context_full_project_export/SKILL.md +28 -28
- package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
- package/assets/skills/context_product_plan/SKILL.md +99 -79
- package/assets/skills/context_surface_contract/SKILL.md +191 -191
- package/assets/skills/context_uiux_design/SKILL.md +171 -171
- package/assets/skills/design-resource-authoring/SKILL.md +86 -84
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +138 -123
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +132 -127
- package/assets/skills/design-resource-authoring/references/resource-selection.md +181 -154
- package/assets/skills/design-system-authoring/SKILL.md +57 -57
- package/assets/skills/design-system-authoring/agents/openai.yaml +6 -6
- package/assets/skills/design-system-authoring/references/authority-adoption.md +48 -48
- package/assets/skills/design-system-authoring/references/open-design-design-system-provider.md +110 -110
- package/assets/skills/long-task-workflow/SKILL.md +98 -92
- package/assets/skills/long-task-workflow/agents/openai.yaml +3 -1
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +72 -72
- package/assets/skills/long-task-workflow/references/contract-authoring.md +122 -101
- package/assets/skills/long-task-workflow/references/evidence-design.md +82 -61
- package/assets/skills/long-task-workflow/references/source-authoring.md +109 -90
- package/assets/skills/source-plan-authoring/SKILL.md +14 -14
- package/assets/tools/validate_context.py +442 -442
- package/dist/commands/long-task-authoring.js +27 -2
- package/dist/lib/context-default-footprint.js +2 -0
- package/dist/lib/context-manifest.js +6 -0
- package/dist/lib/context-templates.js +1 -1
- package/dist/lib/design-resource-fact-enums.d.ts +20 -0
- package/dist/lib/design-resource-fact-enums.js +170 -0
- package/dist/lib/design-resource-fact-locator-extractors.d.ts +8 -0
- package/dist/lib/design-resource-fact-locator-extractors.js +108 -0
- package/dist/lib/design-resource-fact-locator-resolver.d.ts +3 -0
- package/dist/lib/design-resource-fact-locator-resolver.js +112 -0
- package/dist/lib/design-resource-fact-locator-validation.d.ts +5 -0
- package/dist/lib/design-resource-fact-locator-validation.js +16 -0
- package/dist/lib/design-resource-fact-manifest-catalog.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-catalog.js +249 -0
- package/dist/lib/design-resource-fact-manifest-model.d.ts +91 -0
- package/dist/lib/design-resource-fact-manifest-model.js +21 -0
- package/dist/lib/design-resource-fact-manifest-shape-axes.d.ts +6 -0
- package/dist/lib/design-resource-fact-manifest-shape-axes.js +159 -0
- package/dist/lib/design-resource-fact-manifest-shape-evidence.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-shape-evidence.js +59 -0
- package/dist/lib/design-resource-fact-manifest-shape-facts.d.ts +4 -0
- package/dist/lib/design-resource-fact-manifest-shape-facts.js +109 -0
- package/dist/lib/design-resource-fact-manifest-shape-inspector.d.ts +5 -0
- package/dist/lib/design-resource-fact-manifest-shape-inspector.js +144 -0
- package/dist/lib/design-resource-fact-manifest-shape.d.ts +7 -0
- package/dist/lib/design-resource-fact-manifest-shape.js +75 -0
- package/dist/lib/design-resource-fact-manifest-types.d.ts +3 -0
- package/dist/lib/design-resource-fact-manifest-types.js +3 -0
- package/dist/lib/design-resource-fact-manifest-universe.d.ts +5 -0
- package/dist/lib/design-resource-fact-manifest-universe.js +50 -0
- package/dist/lib/design-resource-fact-manifest-validation.d.ts +3 -0
- package/dist/lib/design-resource-fact-manifest-validation.js +106 -0
- package/dist/lib/design-resource-fact-policy.d.ts +18 -0
- package/dist/lib/design-resource-fact-policy.js +72 -1
- package/dist/lib/design-resource-fact-property-methods.d.ts +3 -0
- package/dist/lib/design-resource-fact-property-methods.js +158 -0
- package/dist/lib/design-resource-fact-shape-primitives.d.ts +3 -0
- package/dist/lib/design-resource-fact-shape-primitives.js +18 -0
- package/dist/lib/design-resource-fact-types.d.ts +164 -0
- package/dist/lib/design-resource-fact-types.js +1 -0
- package/dist/lib/design-resource-fact-universe-assets.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-assets.js +71 -0
- package/dist/lib/design-resource-fact-universe-catalog.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-catalog.js +151 -0
- package/dist/lib/design-resource-fact-universe-conditions.d.ts +2 -0
- package/dist/lib/design-resource-fact-universe-conditions.js +92 -0
- package/dist/lib/design-resource-fact-universe-facts.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-facts.js +108 -0
- package/dist/lib/design-resource-fact-universe-helpers.d.ts +30 -0
- package/dist/lib/design-resource-fact-universe-helpers.js +167 -0
- package/dist/lib/design-resource-fact-universe-inspector.d.ts +7 -0
- package/dist/lib/design-resource-fact-universe-inspector.js +119 -0
- package/dist/lib/design-resource-fact-universe-proof.d.ts +4 -0
- package/dist/lib/design-resource-fact-universe-proof.js +113 -0
- package/dist/lib/design-resource-fact-universe-subjects.d.ts +5 -0
- package/dist/lib/design-resource-fact-universe-subjects.js +97 -0
- package/dist/lib/design-resource-fact-universe-variations.d.ts +2 -0
- package/dist/lib/design-resource-fact-universe-variations.js +75 -0
- package/dist/lib/design-resource-fact-value-validation.d.ts +2 -0
- package/dist/lib/design-resource-fact-value-validation.js +80 -0
- package/dist/lib/design-resource-handoff-file-primitives.js +2 -0
- package/dist/lib/design-resource-handoff-file-validation.js +13 -100
- package/dist/lib/design-resource-handoff-policy.d.ts +1 -0
- package/dist/lib/design-resource-handoff-policy.js +118 -11
- package/dist/lib/design-resource-handoff-shape-evidence.js +46 -3
- package/dist/lib/design-resource-handoff-shape-primitives.d.ts +5 -0
- package/dist/lib/design-resource-handoff-shape-primitives.js +28 -0
- package/dist/lib/design-resource-handoff-shape-structure.js +143 -22
- package/dist/lib/design-resource-handoff-shape.js +25 -0
- package/dist/lib/design-resource-handoff-types.d.ts +97 -21
- package/dist/lib/design-resource-handoff-types.js +22 -0
- package/dist/lib/design-resource-handoff-validation-coverage.d.ts +1 -1
- package/dist/lib/design-resource-handoff-validation-coverage.js +145 -118
- package/dist/lib/design-resource-handoff-validation-fact-cells.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-fact-cells.js +60 -0
- package/dist/lib/design-resource-handoff-validation-fact-records.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-fact-records.js +90 -0
- package/dist/lib/design-resource-handoff-validation-facts.js +10 -94
- package/dist/lib/design-resource-handoff-validation-proofs.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation-proofs.js +67 -0
- package/dist/lib/design-resource-handoff-validation-resource-closure.d.ts +3 -0
- package/dist/lib/design-resource-handoff-validation-resource-closure.js +88 -0
- package/dist/lib/design-resource-handoff-validation-structure.js +43 -14
- package/dist/lib/design-resource-handoff-validation.js +32 -0
- package/dist/lib/design-resource-handoff-web-dependency-validation.d.ts +2 -1
- package/dist/lib/design-resource-handoff-web-dependency-validation.js +67 -7
- package/dist/lib/execution-target-capabilities.d.ts +1 -1
- package/dist/lib/execution-target-capabilities.js +14 -0
- package/dist/lib/long-task-activation-validation.js +6 -2
- package/dist/lib/long-task-applicability-shape.js +3 -3
- package/dist/lib/long-task-authoring-authority-preview.js +1 -0
- package/dist/lib/long-task-authority-policy.d.ts +1 -0
- package/dist/lib/long-task-authority-policy.js +1 -0
- package/dist/lib/long-task-authority.js +13 -0
- package/dist/lib/long-task-claim-definitions.js +13 -1
- package/dist/lib/long-task-claims.js +23 -1
- package/dist/lib/long-task-contract-types.d.ts +3 -0
- package/dist/lib/long-task-delivery-compiler.js +1 -0
- package/dist/lib/long-task-delivery-parser.js +11 -1
- 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 +17 -0
- package/dist/lib/long-task-design-resource-handoff.js +62 -38
- package/dist/lib/long-task-design-target-capabilities.d.ts +14 -0
- package/dist/lib/long-task-design-target-capabilities.js +126 -0
- package/dist/lib/long-task-evidence-capability-codec.d.ts +94 -0
- package/dist/lib/long-task-evidence-capability-codec.js +395 -22
- package/dist/lib/long-task-evidence-capability-policy.js +18 -0
- package/dist/lib/long-task-evidence-capability-runtime.js +78 -0
- package/dist/lib/long-task-evidence-capability-types.d.ts +114 -1
- package/dist/lib/long-task-outcome-parser.js +4 -0
- package/dist/lib/long-task-playwright-capability-records.d.ts +5 -0
- package/dist/lib/long-task-playwright-capability-records.js +146 -0
- package/dist/lib/long-task-playwright-case-evidence.d.ts +3 -2
- package/dist/lib/long-task-playwright-case-evidence.js +10 -79
- package/dist/lib/long-task-playwright-case-primitives.d.ts +28 -0
- package/dist/lib/long-task-playwright-case-primitives.js +143 -0
- package/dist/lib/long-task-playwright-evidence.d.ts +1 -1
- package/dist/lib/long-task-playwright-evidence.js +10 -75
- package/dist/lib/long-task-runner-freeze.d.ts +2 -2
- package/dist/lib/long-task-runner-freeze.js +15 -1
- package/dist/lib/long-task-runtime-types.d.ts +4 -1
- package/dist/lib/long-task-semantic-contract-types.d.ts +1 -1
- package/dist/lib/long-task-semantic-drift-migration.js +2 -2
- package/dist/lib/long-task-semantic-fact-binding-types.d.ts +57 -0
- package/dist/lib/long-task-semantic-fact-binding-types.js +1 -0
- package/dist/lib/long-task-semantic-fact-closure-primitives.d.ts +5 -0
- package/dist/lib/long-task-semantic-fact-closure-primitives.js +43 -0
- package/dist/lib/long-task-semantic-fact-closure.d.ts +13 -0
- package/dist/lib/long-task-semantic-fact-closure.js +48 -0
- package/dist/lib/long-task-semantic-fact-contract-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-closure.js +24 -0
- package/dist/lib/long-task-semantic-fact-contract-facts.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-facts.js +30 -0
- package/dist/lib/long-task-semantic-fact-contract-proofs.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-contract-proofs.js +97 -0
- package/dist/lib/long-task-semantic-fact-evidence.d.ts +21 -0
- package/dist/lib/long-task-semantic-fact-evidence.js +165 -0
- package/dist/lib/long-task-semantic-fact-input-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-input-closure.js +101 -0
- package/dist/lib/long-task-semantic-fact-provenance-closure.d.ts +4 -0
- package/dist/lib/long-task-semantic-fact-provenance-closure.js +140 -0
- package/dist/lib/long-task-semantic-fact-shape.d.ts +3 -0
- package/dist/lib/long-task-semantic-fact-shape.js +89 -0
- package/dist/lib/long-task-semantic-fact-value-closure.d.ts +3 -0
- package/dist/lib/long-task-semantic-fact-value-closure.js +110 -0
- package/dist/lib/long-task-shape-primitives.d.ts +2 -1
- package/dist/lib/long-task-shape-primitives.js +7 -0
- package/dist/lib/long-task-source-item-parser.js +25 -6
- package/dist/lib/long-task-source-target-continuity.js +4 -1
- package/dist/lib/long-task-source-target-index.d.ts +1 -1
- package/dist/lib/long-task-source-target-index.js +5 -1
- package/dist/lib/long-task-ui-design-policy.js +8 -4
- package/dist/lib/long-task-ui-surface-shape.js +83 -1
- package/dist/lib/long-task-ui-surface-types.d.ts +29 -0
- package/dist/lib/modularity.js +7 -1
- package/dist/lib/semantic-fact-base-types.d.ts +14 -0
- package/dist/lib/semantic-fact-base-types.js +1 -0
- package/dist/lib/semantic-fact-catalog.d.ts +8 -0
- package/dist/lib/semantic-fact-catalog.js +191 -0
- package/dist/lib/semantic-fact-condition-shape.d.ts +48 -0
- package/dist/lib/semantic-fact-condition-shape.js +111 -0
- package/dist/lib/semantic-fact-input-shape.d.ts +34 -0
- package/dist/lib/semantic-fact-input-shape.js +111 -0
- package/dist/lib/semantic-fact-inventory-types.d.ts +147 -0
- package/dist/lib/semantic-fact-inventory-types.js +1 -0
- package/dist/lib/semantic-fact-manifest-shape.d.ts +4 -0
- package/dist/lib/semantic-fact-manifest-shape.js +135 -0
- package/dist/lib/semantic-fact-manifest-types.d.ts +58 -0
- package/dist/lib/semantic-fact-manifest-types.js +19 -0
- package/dist/lib/semantic-fact-policy-authority.d.ts +8 -0
- package/dist/lib/semantic-fact-policy-authority.js +79 -0
- package/dist/lib/semantic-fact-policy-census.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-census.js +80 -0
- package/dist/lib/semantic-fact-policy-condition-references.d.ts +7 -0
- package/dist/lib/semantic-fact-policy-condition-references.js +19 -0
- package/dist/lib/semantic-fact-policy-conditions.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-conditions.js +105 -0
- package/dist/lib/semantic-fact-policy-facts.d.ts +3 -0
- package/dist/lib/semantic-fact-policy-facts.js +73 -0
- package/dist/lib/semantic-fact-policy-primitives.d.ts +26 -0
- package/dist/lib/semantic-fact-policy-primitives.js +169 -0
- package/dist/lib/semantic-fact-policy-proofs.d.ts +2 -0
- package/dist/lib/semantic-fact-policy-proofs.js +75 -0
- package/dist/lib/semantic-fact-policy-properties.d.ts +3 -0
- package/dist/lib/semantic-fact-policy-properties.js +84 -0
- package/dist/lib/semantic-fact-policy-units.d.ts +4 -0
- package/dist/lib/semantic-fact-policy-units.js +103 -0
- package/dist/lib/semantic-fact-policy.d.ts +17 -0
- package/dist/lib/semantic-fact-policy.js +41 -0
- package/dist/lib/semantic-fact-proof-shape.d.ts +51 -0
- package/dist/lib/semantic-fact-proof-shape.js +121 -0
- package/dist/lib/semantic-fact-proof-types.d.ts +74 -0
- package/dist/lib/semantic-fact-proof-types.js +1 -0
- package/dist/lib/semantic-fact-property-shape.d.ts +29 -0
- package/dist/lib/semantic-fact-property-shape.js +77 -0
- package/dist/lib/semantic-fact-shape-constants.d.ts +3 -0
- package/dist/lib/semantic-fact-shape-constants.js +38 -0
- package/dist/lib/semantic-fact-shape-primitives.d.ts +15 -0
- package/dist/lib/semantic-fact-shape-primitives.js +68 -0
- package/dist/lib/semantic-fact-source-parser.d.ts +9 -0
- package/dist/lib/semantic-fact-source-parser.js +46 -0
- package/dist/lib/semantic-fact-support-shape.d.ts +21 -0
- package/dist/lib/semantic-fact-support-shape.js +59 -0
- package/dist/lib/semantic-fact-types.d.ts +5 -0
- package/dist/lib/semantic-fact-types.js +5 -0
- package/dist/lib/semantic-fact-unit-shape.d.ts +34 -0
- package/dist/lib/semantic-fact-unit-shape.js +89 -0
- package/dist/lib/semantic-fact-value-shape.d.ts +12 -0
- package/dist/lib/semantic-fact-value-shape.js +39 -0
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +1339 -131
- package/migrations/README.md +15 -15
- package/package.json +84 -84
- package/source-mappings.yaml +25 -25
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { canonicalValueJson, sha256Hex } from "./strict-codec.js";
|
|
2
|
+
export function validateSemanticFactEvidence(check, record, artifactHashes) {
|
|
3
|
+
const expectations = check.semantic_fact_expectations.filter((item) => item.assertion_ref === record.assertion_key);
|
|
4
|
+
if (expectations.length !== 1)
|
|
5
|
+
return expectations.length
|
|
6
|
+
? "semantic_fact_expectation_duplicate"
|
|
7
|
+
: "semantic_fact_expectation_missing";
|
|
8
|
+
const expected = expectations[0];
|
|
9
|
+
const authorityError = validateSemanticFactEvidenceAuthority(check, record, expected);
|
|
10
|
+
if (authorityError)
|
|
11
|
+
return authorityError;
|
|
12
|
+
const artifactError = validateSemanticFactArtifacts(record, expected, artifactHashes);
|
|
13
|
+
if (artifactError)
|
|
14
|
+
return artifactError;
|
|
15
|
+
const observerError = validateSemanticFactObservers(record, expected, artifactHashes);
|
|
16
|
+
if (observerError)
|
|
17
|
+
return observerError;
|
|
18
|
+
if (record.verdict !== "passed" || record.comparison.passed !== true)
|
|
19
|
+
return "semantic_fact_failed";
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function validateSemanticFactEvidenceAuthority(check, record, expected) {
|
|
23
|
+
if (!sameSemanticFactIdentity(record, expected))
|
|
24
|
+
return "semantic_fact_identity_mismatch";
|
|
25
|
+
if (record.target_ref !== check.execution_target.target_ref ||
|
|
26
|
+
expected.check_ref !== check.key)
|
|
27
|
+
return "semantic_fact_target_mismatch";
|
|
28
|
+
if (record.actual_observation.sensitivity !== expected.observation_sensitivity)
|
|
29
|
+
return "semantic_fact_sensitivity_mismatch";
|
|
30
|
+
if (!validSemanticFactRedaction(record.actual_observation.sensitivity, record.actual_observation.redaction))
|
|
31
|
+
return "semantic_fact_redaction_mismatch";
|
|
32
|
+
if (canonicalValueJson(record.expected) !==
|
|
33
|
+
canonicalValueJson(expected.expected))
|
|
34
|
+
return "semantic_fact_expected_value_mismatch";
|
|
35
|
+
if (!sameSemanticFactComparisonAuthority(record, expected))
|
|
36
|
+
return "semantic_fact_comparison_authority_mismatch";
|
|
37
|
+
if (record.comparison.result_sha256 !==
|
|
38
|
+
semanticFactComparisonResultIdentity({
|
|
39
|
+
fact_ref: record.fact_ref,
|
|
40
|
+
proof_ref: record.proof_ref,
|
|
41
|
+
target_ref: record.target_ref,
|
|
42
|
+
actual_value_sha256: record.actual_observation.value_sha256,
|
|
43
|
+
expected_value_sha256: expected.expected.sha256,
|
|
44
|
+
comparator: record.comparison.comparator,
|
|
45
|
+
mode: record.comparison.mode,
|
|
46
|
+
parameters_sha256: record.comparison.parameters.sha256,
|
|
47
|
+
tolerance_sha256: record.comparison.tolerance?.sha256 ?? null,
|
|
48
|
+
mask_sha256: record.comparison.mask?.sha256 ?? null,
|
|
49
|
+
passed: record.comparison.passed,
|
|
50
|
+
}))
|
|
51
|
+
return "semantic_fact_comparison_result_identity_mismatch";
|
|
52
|
+
if (record.comparison.comparator === "exact_value" &&
|
|
53
|
+
record.actual_observation.value_sha256 !== expected.expected.sha256)
|
|
54
|
+
return "semantic_fact_exact_value_mismatch";
|
|
55
|
+
if (canonicalValueJson(record.oracle) !== canonicalValueJson(expected.oracle) ||
|
|
56
|
+
canonicalValueJson(record.environment) !==
|
|
57
|
+
canonicalValueJson(expected.environment))
|
|
58
|
+
return "semantic_fact_oracle_environment_mismatch";
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function sameSemanticFactIdentity(record, expected) {
|
|
62
|
+
return (record.manifest_ref === expected.manifest_ref &&
|
|
63
|
+
record.manifest_sha256 === expected.manifest_sha256 &&
|
|
64
|
+
record.outcome_ref === expected.outcome_ref &&
|
|
65
|
+
record.fact_ref === expected.fact_ref &&
|
|
66
|
+
record.proof_ref === expected.proof_ref &&
|
|
67
|
+
record.method === expected.method &&
|
|
68
|
+
record.subject_ref === expected.subject_ref &&
|
|
69
|
+
record.condition_ref === expected.condition_ref &&
|
|
70
|
+
record.property_ref === expected.property_ref);
|
|
71
|
+
}
|
|
72
|
+
function validSemanticFactRedaction(sensitivity, redaction) {
|
|
73
|
+
return ((sensitivity === "plain" && redaction === null) ||
|
|
74
|
+
(sensitivity === "protected" && redaction !== null));
|
|
75
|
+
}
|
|
76
|
+
function sameSemanticFactComparisonAuthority(record, expected) {
|
|
77
|
+
return (record.comparison.comparator === expected.comparison.comparator &&
|
|
78
|
+
record.comparison.mode === expected.comparison.mode &&
|
|
79
|
+
canonicalValueJson(record.comparison.parameters) ===
|
|
80
|
+
canonicalValueJson(expected.comparison.parameters) &&
|
|
81
|
+
canonicalValueJson(record.comparison.tolerance) ===
|
|
82
|
+
canonicalValueJson(expected.comparison.tolerance) &&
|
|
83
|
+
canonicalValueJson(record.comparison.mask) ===
|
|
84
|
+
canonicalValueJson(expected.comparison.mask));
|
|
85
|
+
}
|
|
86
|
+
function validateSemanticFactArtifacts(record, expected, artifactHashes) {
|
|
87
|
+
if (artifactHashes[record.actual_observation.artifact_path] !==
|
|
88
|
+
record.actual_observation.artifact_sha256)
|
|
89
|
+
return "semantic_fact_observation_artifact_mismatch";
|
|
90
|
+
if (artifactHashes[record.actual_environment.artifact_path] !==
|
|
91
|
+
record.actual_environment.artifact_sha256 ||
|
|
92
|
+
record.actual_environment.value_sha256 !==
|
|
93
|
+
expected.environment.definition.sha256)
|
|
94
|
+
return "semantic_fact_environment_observation_mismatch";
|
|
95
|
+
if (artifactHashes[record.comparison.artifact_path] !==
|
|
96
|
+
record.comparison.artifact_sha256)
|
|
97
|
+
return "semantic_fact_comparison_artifact_mismatch";
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
function validateSemanticFactObservers(record, expected, artifactHashes) {
|
|
101
|
+
if (!sameSet(record.observer_results.map((item) => item.target_ref), expected.observer_refs))
|
|
102
|
+
return "semantic_fact_observer_set_mismatch";
|
|
103
|
+
const observerObservations = new Set();
|
|
104
|
+
const primaryObservation = `${record.actual_observation.artifact_path}\0${canonicalValueJson(record.actual_observation.locator)}`;
|
|
105
|
+
for (const observer of record.observer_results) {
|
|
106
|
+
const observation = `${observer.artifact_path}\0${canonicalValueJson(observer.locator)}`;
|
|
107
|
+
if (observation === primaryObservation ||
|
|
108
|
+
observerObservations.has(observation))
|
|
109
|
+
return "semantic_fact_observer_observation_reused";
|
|
110
|
+
observerObservations.add(observation);
|
|
111
|
+
if (artifactHashes[observer.artifact_path] !== observer.artifact_sha256)
|
|
112
|
+
return "semantic_fact_observer_artifact_mismatch";
|
|
113
|
+
if (observer.passed !== true ||
|
|
114
|
+
(record.comparison.comparator === "exact_value" &&
|
|
115
|
+
observer.value_sha256 !== expected.expected.sha256))
|
|
116
|
+
return "semantic_fact_observer_failed";
|
|
117
|
+
if (observer.comparison_result_sha256 !==
|
|
118
|
+
semanticFactComparisonResultIdentity({
|
|
119
|
+
fact_ref: record.fact_ref,
|
|
120
|
+
proof_ref: record.proof_ref,
|
|
121
|
+
target_ref: observer.target_ref,
|
|
122
|
+
actual_value_sha256: observer.value_sha256,
|
|
123
|
+
expected_value_sha256: expected.expected.sha256,
|
|
124
|
+
comparator: record.comparison.comparator,
|
|
125
|
+
mode: record.comparison.mode,
|
|
126
|
+
parameters_sha256: record.comparison.parameters.sha256,
|
|
127
|
+
tolerance_sha256: record.comparison.tolerance?.sha256 ?? null,
|
|
128
|
+
mask_sha256: record.comparison.mask?.sha256 ?? null,
|
|
129
|
+
passed: observer.passed,
|
|
130
|
+
}))
|
|
131
|
+
return "semantic_fact_observer_comparison_identity_mismatch";
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
export function semanticFactComparisonResultIdentity(value) {
|
|
136
|
+
return sha256Hex(canonicalValueJson(value));
|
|
137
|
+
}
|
|
138
|
+
export function validateDistinctSemanticFactEvidence(records) {
|
|
139
|
+
const observations = new Set();
|
|
140
|
+
const comparisons = new Set();
|
|
141
|
+
const identities = new Set();
|
|
142
|
+
for (const record of records) {
|
|
143
|
+
if (record.capability !== "semantic_fact")
|
|
144
|
+
continue;
|
|
145
|
+
const identity = `${record.fact_ref}\0${record.proof_ref}`;
|
|
146
|
+
if (identities.has(identity))
|
|
147
|
+
return "semantic_fact_result_duplicate";
|
|
148
|
+
identities.add(identity);
|
|
149
|
+
const observation = `${record.actual_observation.artifact_path}\0${canonicalValueJson(record.actual_observation.locator)}`;
|
|
150
|
+
if (observations.has(observation))
|
|
151
|
+
return "semantic_fact_observation_reused";
|
|
152
|
+
observations.add(observation);
|
|
153
|
+
const comparison = `${record.comparison.artifact_path}\0${canonicalValueJson(record.comparison.locator)}`;
|
|
154
|
+
if (comparisons.has(comparison))
|
|
155
|
+
return "semantic_fact_comparison_reused";
|
|
156
|
+
comparisons.add(comparison);
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
function sameSet(left, right) {
|
|
161
|
+
return (left.length === right.length &&
|
|
162
|
+
new Set(left).size === left.length &&
|
|
163
|
+
left.every((item) => right.includes(item)));
|
|
164
|
+
}
|
|
165
|
+
export const typed_semantic_fact_runtime_evidence = "fact_ref+actual+comparison+verdict+oracle+environment";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledSourceItemV2 } from "./long-task-source-authority-types.js";
|
|
2
|
+
import type { SemanticFactManifestV1 } from "./semantic-fact-types.js";
|
|
3
|
+
export declare function collectDesignOwnedSemanticFactSourceItems(repository: string, sourcePaths: string[]): Promise<Set<string>>;
|
|
4
|
+
export declare function validateSemanticFactInputInventory(repository: string, sourceItems: CompiledSourceItemV2[], contextFiles: string[], manifest: SemanticFactManifestV1, designOwnedSourceItems: Set<string>): Promise<void>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { containsDesignResourceHandoff, parseDesignResourceHandoffMarkdown, } from "./design-resource-handoff-parser.js";
|
|
4
|
+
import { assertSameSemanticFactClosureSet, semanticFactClosureInvalid, uniqueSemanticFactClosureValues, } from "./long-task-semantic-fact-closure-primitives.js";
|
|
5
|
+
import { validateSemanticFactProvenance } from "./long-task-semantic-fact-provenance-closure.js";
|
|
6
|
+
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
7
|
+
import { sha256Hex } from "./strict-codec.js";
|
|
8
|
+
export async function collectDesignOwnedSemanticFactSourceItems(repository, sourcePaths) {
|
|
9
|
+
const result = new Set();
|
|
10
|
+
for (const sourcePath of sourcePaths) {
|
|
11
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...sourcePath.split("/")), `semantic_fact_design_source:${sourcePath}`);
|
|
12
|
+
const content = await readFile(file, "utf8");
|
|
13
|
+
if (!containsDesignResourceHandoff(content))
|
|
14
|
+
continue;
|
|
15
|
+
const parsed = parseDesignResourceHandoffMarkdown(sourcePath, content);
|
|
16
|
+
for (const key of parsed.source_item_keys)
|
|
17
|
+
result.add(key);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
export async function validateSemanticFactInputInventory(repository, sourceItems, contextFiles, manifest, designOwnedSourceItems) {
|
|
22
|
+
const sourceItemByKey = new Map(sourceItems.map((item) => [item.key, item]));
|
|
23
|
+
const sourceInputs = manifest.inputs.filter((item) => item.kind === "source_item");
|
|
24
|
+
assertSameSemanticFactClosureSet(manifest.scope.source_item_refs, sourceItems.map((item) => item.key), "manifest_source_item_universe");
|
|
25
|
+
assertSameSemanticFactClosureSet(sourceInputs.map((item) => item.source_ref), sourceItems.map((item) => item.key), "input_source_item_universe");
|
|
26
|
+
validateSourceInputDigests(sourceInputs, sourceItemByKey, designOwnedSourceItems);
|
|
27
|
+
const contextInputs = manifest.inputs.filter((item) => item.kind === "context");
|
|
28
|
+
assertSameSemanticFactClosureSet(contextInputs.map((item) => item.source_ref), contextFiles, "input_context_universe");
|
|
29
|
+
for (const input of manifest.inputs)
|
|
30
|
+
await validateInput(repository, manifest, input, designOwnedSourceItems);
|
|
31
|
+
validateInputFactLineage(manifest, sourceInputs);
|
|
32
|
+
validateSemanticFactProvenance(manifest, sourceItems);
|
|
33
|
+
}
|
|
34
|
+
function validateSourceInputDigests(sourceInputs, sourceItemByKey, designOwnedSourceItems) {
|
|
35
|
+
for (const input of sourceInputs) {
|
|
36
|
+
const sourceItem = sourceItemByKey.get(input.source_ref);
|
|
37
|
+
if (input.sha256 !== sourceItem.text_sha256)
|
|
38
|
+
semanticFactClosureInvalid("input_source_item_digest_mismatch", `${input.key}:${input.source_ref}`);
|
|
39
|
+
const designOwned = designOwnedSourceItems.has(input.source_ref);
|
|
40
|
+
if (designOwned
|
|
41
|
+
? !["ui_design", "non_ui_material"].includes(input.disposition)
|
|
42
|
+
: input.disposition !== "non_ui_material")
|
|
43
|
+
semanticFactClosureInvalid("material_source_item_disposition_mismatch", `${input.key}:${input.source_ref}:${input.disposition}:${designOwned ? "ui_design_or_non_ui_material" : "non_ui_material"}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function validateInput(repository, manifest, input, designOwnedSourceItems) {
|
|
47
|
+
uniqueSemanticFactClosureValues(input.fact_refs, `input_fact_refs:${input.key}`);
|
|
48
|
+
uniqueSemanticFactClosureValues(input.basis_refs, `input_basis_refs:${input.key}`);
|
|
49
|
+
if (input.disposition === "non_ui_material"
|
|
50
|
+
? !input.fact_refs.length
|
|
51
|
+
: input.fact_refs.length)
|
|
52
|
+
semanticFactClosureInvalid("input_fact_disposition_mismatch", `${input.key}:${input.disposition}`);
|
|
53
|
+
if (input.disposition !== "non_ui_material" && !input.rationale.trim())
|
|
54
|
+
semanticFactClosureInvalid("input_disposition_rationale_required", input.key);
|
|
55
|
+
if (["canonical_spec", "external_constraint", "delegated_instruction"].includes(input.kind) &&
|
|
56
|
+
input.disposition !== "non_ui_material")
|
|
57
|
+
semanticFactClosureInvalid("material_input_disposition_mismatch", `${input.key}:${input.kind}:${input.disposition}`);
|
|
58
|
+
const uiDesignInput = input.kind === "design_resource" ||
|
|
59
|
+
(input.kind === "source_item" &&
|
|
60
|
+
designOwnedSourceItems.has(input.source_ref));
|
|
61
|
+
if (uiDesignInput
|
|
62
|
+
? !["ui_design", "non_ui_material"].includes(input.disposition)
|
|
63
|
+
: input.disposition === "ui_design")
|
|
64
|
+
semanticFactClosureInvalid("ui_design_input_kind_mismatch", `${input.key}:${input.kind}:${input.disposition}`);
|
|
65
|
+
if (input.disposition === "excluded_by_scope" &&
|
|
66
|
+
!manifest.scope.exclusions.some((exclusion) => exclusion.affected_refs.includes(input.key)))
|
|
67
|
+
semanticFactClosureInvalid("input_scope_exclusion_missing", input.key);
|
|
68
|
+
if (input.kind === "source_item")
|
|
69
|
+
return;
|
|
70
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...input.source_ref.split("/")), `semantic_fact_input:${input.key}`);
|
|
71
|
+
const digest = sha256Hex(await readFile(file));
|
|
72
|
+
if (digest !== input.sha256)
|
|
73
|
+
semanticFactClosureInvalid("input_resource_digest_mismatch", `${input.key}:${input.source_ref}`);
|
|
74
|
+
}
|
|
75
|
+
function validateInputFactLineage(manifest, sourceInputs) {
|
|
76
|
+
const facts = new Map(manifest.facts.map((item) => [item.key, item]));
|
|
77
|
+
for (const input of manifest.inputs)
|
|
78
|
+
for (const factRef of input.fact_refs)
|
|
79
|
+
if (!facts.has(factRef))
|
|
80
|
+
semanticFactClosureInvalid("input_fact_unknown", `${input.key}:${factRef}`);
|
|
81
|
+
else {
|
|
82
|
+
const fact = facts.get(factRef);
|
|
83
|
+
if (input.kind === "source_item"
|
|
84
|
+
? !fact.source_item_refs.includes(input.source_ref)
|
|
85
|
+
: !fact.provenance.basis_refs.includes(input.key))
|
|
86
|
+
semanticFactClosureInvalid("input_fact_lineage_mismatch", `${input.key}:${factRef}`);
|
|
87
|
+
}
|
|
88
|
+
for (const fact of manifest.facts) {
|
|
89
|
+
const sourceInputRefs = fact.source_item_refs.map((sourceItemRef) => {
|
|
90
|
+
const input = sourceInputs.find((item) => item.source_ref === sourceItemRef);
|
|
91
|
+
if (!input)
|
|
92
|
+
semanticFactClosureInvalid("fact_source_input_missing", `${fact.key}:${sourceItemRef}`);
|
|
93
|
+
if (input.disposition !== "non_ui_material" ||
|
|
94
|
+
!input.fact_refs.includes(fact.key))
|
|
95
|
+
semanticFactClosureInvalid("fact_source_input_lineage_mismatch", `${fact.key}:${input.key}`);
|
|
96
|
+
return input.key;
|
|
97
|
+
});
|
|
98
|
+
if (!sourceInputRefs.length)
|
|
99
|
+
semanticFactClosureInvalid("fact_source_input_required", fact.key);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompiledSourceItemV2 } from "./long-task-source-authority-types.js";
|
|
2
|
+
import type { SemanticFactManifestV1 } from "./semantic-fact-types.js";
|
|
3
|
+
export declare function validateSemanticFactProvenance(manifest: SemanticFactManifestV1, sourceItems: CompiledSourceItemV2[]): void;
|
|
4
|
+
export declare function validateSemanticFactBasisClosure(manifest: SemanticFactManifestV1, sourceItems: CompiledSourceItemV2[]): void;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { semanticFactClosureInvalid } from "./long-task-semantic-fact-closure-primitives.js";
|
|
2
|
+
export function validateSemanticFactProvenance(manifest, sourceItems) {
|
|
3
|
+
const sourceRefs = new Set(sourceItems.map((item) => item.key));
|
|
4
|
+
const inputByKey = new Map(manifest.inputs.map((item) => [item.key, item]));
|
|
5
|
+
const materialInputRefs = new Set(manifest.inputs
|
|
6
|
+
.filter((item) => item.disposition === "non_ui_material")
|
|
7
|
+
.map((item) => item.key));
|
|
8
|
+
const facts = new Map(manifest.facts.map((item) => [item.key, item]));
|
|
9
|
+
const isMaterialAuthority = (ref) => sourceRefs.has(ref) || materialInputRefs.has(ref);
|
|
10
|
+
for (const fact of manifest.facts)
|
|
11
|
+
validateFactAuthority(fact, facts, sourceRefs, inputByKey, isMaterialAuthority);
|
|
12
|
+
const grounded = new Map();
|
|
13
|
+
const visit = (factRef, active) => {
|
|
14
|
+
const cached = grounded.get(factRef);
|
|
15
|
+
if (cached !== undefined)
|
|
16
|
+
return cached;
|
|
17
|
+
if (active.has(factRef))
|
|
18
|
+
semanticFactClosureInvalid("fact_provenance_cycle", [...active, factRef].join("->"));
|
|
19
|
+
const fact = facts.get(factRef);
|
|
20
|
+
const next = new Set(active);
|
|
21
|
+
next.add(factRef);
|
|
22
|
+
const result = fact.provenance.basis_refs.some((ref) => isMaterialAuthority(ref) || (facts.has(ref) && visit(ref, next)));
|
|
23
|
+
grounded.set(factRef, result);
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
for (const fact of manifest.facts)
|
|
27
|
+
if (!visit(fact.key, new Set()))
|
|
28
|
+
semanticFactClosureInvalid("fact_provenance_ungrounded", fact.key);
|
|
29
|
+
}
|
|
30
|
+
function validateFactAuthority(fact, facts, sourceRefs, inputByKey, isMaterialAuthority) {
|
|
31
|
+
const authorityRef = fact.provenance.authority_ref;
|
|
32
|
+
if (!fact.provenance.basis_refs.includes(authorityRef))
|
|
33
|
+
semanticFactClosureInvalid("fact_authority_basis_missing", `${fact.key}:${authorityRef}`);
|
|
34
|
+
if (authorityRef === fact.key)
|
|
35
|
+
semanticFactClosureInvalid("fact_authority_self_reference", fact.key);
|
|
36
|
+
if (!isMaterialAuthority(authorityRef) && !facts.has(authorityRef))
|
|
37
|
+
semanticFactClosureInvalid("fact_authority_not_groundable", `${fact.key}:${authorityRef}`);
|
|
38
|
+
if (fact.provenance.kind !== "logically_derived" &&
|
|
39
|
+
!isMaterialAuthority(authorityRef))
|
|
40
|
+
semanticFactClosureInvalid("fact_direct_authority_required", `${fact.key}:${fact.provenance.kind}:${authorityRef}`);
|
|
41
|
+
if (sourceRefs.has(authorityRef) &&
|
|
42
|
+
!fact.source_item_refs.includes(authorityRef))
|
|
43
|
+
semanticFactClosureInvalid("fact_authority_source_lineage_mismatch", `${fact.key}:${authorityRef}`);
|
|
44
|
+
const authorityInput = inputByKey.get(authorityRef);
|
|
45
|
+
if (authorityInput && !authorityInput.fact_refs.includes(fact.key))
|
|
46
|
+
semanticFactClosureInvalid("fact_authority_input_lineage_mismatch", `${fact.key}:${authorityRef}`);
|
|
47
|
+
if (fact.provenance.kind === "explicitly_delegated" &&
|
|
48
|
+
authorityInput &&
|
|
49
|
+
authorityInput.kind !== "delegated_instruction" &&
|
|
50
|
+
authorityInput.kind !== "source_item")
|
|
51
|
+
semanticFactClosureInvalid("delegated_fact_authority_kind_mismatch", `${fact.key}:${authorityInput.kind}`);
|
|
52
|
+
if (fact.provenance.kind === "evidence_backed_preservation" &&
|
|
53
|
+
authorityInput &&
|
|
54
|
+
!["repository_preservation", "context", "source_item"].includes(authorityInput.kind))
|
|
55
|
+
semanticFactClosureInvalid("preservation_fact_authority_kind_mismatch", `${fact.key}:${authorityInput.kind}`);
|
|
56
|
+
}
|
|
57
|
+
export function validateSemanticFactBasisClosure(manifest, sourceItems) {
|
|
58
|
+
const known = semanticFactKnownBasisRefs(manifest, sourceItems);
|
|
59
|
+
const rows = [];
|
|
60
|
+
const collect = (label, values) => rows.push(...values.map((item) => ({
|
|
61
|
+
label: `${label}:${item.key}`,
|
|
62
|
+
refs: item.basis_refs,
|
|
63
|
+
})));
|
|
64
|
+
collect("scope_exclusion", manifest.scope.exclusions);
|
|
65
|
+
collect("input", manifest.inputs);
|
|
66
|
+
collect("census", manifest.inspector.census);
|
|
67
|
+
collect("family", manifest.family_dispositions);
|
|
68
|
+
collect("subject", manifest.subjects);
|
|
69
|
+
collect("relation", manifest.relations);
|
|
70
|
+
collect("population", manifest.populations);
|
|
71
|
+
collect("axis", manifest.axis_dispositions);
|
|
72
|
+
collect("axis_value", manifest.axis_dispositions.flatMap((item) => item.values));
|
|
73
|
+
collect("condition_rule", manifest.condition_rules);
|
|
74
|
+
collect("condition", manifest.conditions);
|
|
75
|
+
collect("condition_exclusion", manifest.condition_exclusions);
|
|
76
|
+
collect("property", manifest.property_dispositions);
|
|
77
|
+
collect("fact_cell", manifest.fact_cells);
|
|
78
|
+
addSpecialBasisRows(manifest, rows);
|
|
79
|
+
for (const row of rows)
|
|
80
|
+
for (const ref of row.refs)
|
|
81
|
+
if (!known.has(ref))
|
|
82
|
+
semanticFactClosureInvalid("basis_ref_unknown", `${row.label}:${ref}`);
|
|
83
|
+
}
|
|
84
|
+
function semanticFactKnownBasisRefs(manifest, sourceItems) {
|
|
85
|
+
return new Set([
|
|
86
|
+
manifest.key,
|
|
87
|
+
...sourceItems.map((item) => item.key),
|
|
88
|
+
...manifest.scope.exclusions.map((item) => item.key),
|
|
89
|
+
...manifest.inputs.map((item) => item.key),
|
|
90
|
+
...manifest.inspector.census.map((item) => item.key),
|
|
91
|
+
...manifest.family_dispositions.map((item) => item.key),
|
|
92
|
+
...manifest.subjects.map((item) => item.key),
|
|
93
|
+
...manifest.relations.map((item) => item.key),
|
|
94
|
+
...manifest.populations.map((item) => item.key),
|
|
95
|
+
...manifest.axis_dispositions.map((item) => item.key),
|
|
96
|
+
...manifest.axis_dispositions.flatMap((item) => item.values.map((value) => value.key)),
|
|
97
|
+
...manifest.condition_rules.map((item) => item.key),
|
|
98
|
+
...manifest.conditions.map((item) => item.key),
|
|
99
|
+
...manifest.condition_exclusions.map((item) => item.key),
|
|
100
|
+
...manifest.property_dispositions.map((item) => item.key),
|
|
101
|
+
...manifest.fact_cells.map((item) => item.key),
|
|
102
|
+
...manifest.facts.map((item) => item.key),
|
|
103
|
+
...manifest.proof_obligations.map((item) => item.key),
|
|
104
|
+
...manifest.oracles.map((item) => item.key),
|
|
105
|
+
...manifest.environments.map((item) => item.key),
|
|
106
|
+
...manifest.blockers.map((item) => item.key),
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
function addSpecialBasisRows(manifest, rows) {
|
|
110
|
+
for (const fact of manifest.facts)
|
|
111
|
+
rows.push({
|
|
112
|
+
label: `fact_provenance:${fact.key}`,
|
|
113
|
+
refs: fact.provenance.basis_refs,
|
|
114
|
+
});
|
|
115
|
+
for (const proof of manifest.proof_obligations)
|
|
116
|
+
rows.push({
|
|
117
|
+
label: `proof_counterfactual:${proof.key}`,
|
|
118
|
+
refs: proof.counterfactual.basis_refs,
|
|
119
|
+
});
|
|
120
|
+
for (const exclusion of manifest.scope.exclusions)
|
|
121
|
+
rows.push({
|
|
122
|
+
label: `scope_exclusion_affected:${exclusion.key}`,
|
|
123
|
+
refs: exclusion.affected_refs,
|
|
124
|
+
});
|
|
125
|
+
for (const population of manifest.populations)
|
|
126
|
+
rows.push({
|
|
127
|
+
label: `population_exclusions:${population.key}`,
|
|
128
|
+
refs: population.exclusion_refs,
|
|
129
|
+
});
|
|
130
|
+
for (const blocker of manifest.blockers)
|
|
131
|
+
rows.push({
|
|
132
|
+
label: `blocker_affected:${blocker.key}`,
|
|
133
|
+
refs: blocker.affected_refs,
|
|
134
|
+
});
|
|
135
|
+
for (const fact of manifest.facts)
|
|
136
|
+
rows.push({
|
|
137
|
+
label: `fact_authority:${fact.key}`,
|
|
138
|
+
refs: [fact.provenance.authority_ref],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SemanticFactManifestRefV2, SemanticFactOutcomeBindingsV2 } from "./semantic-fact-types.js";
|
|
2
|
+
export declare function parseSemanticFactManifestRef(value: unknown, label: string): SemanticFactManifestRefV2;
|
|
3
|
+
export declare function parseSemanticFactOutcomeBindings(value: unknown, label: string): SemanticFactOutcomeBindingsV2;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { array, EVIDENCE_CAPABILITIES, fail, literal, object, PROOF_SURFACES, repositoryFile, string, } from "./long-task-delivery-shape.js";
|
|
2
|
+
export function parseSemanticFactManifestRef(value, label) {
|
|
3
|
+
const row = object(value, label, ["key", "source_path", "sha256"]);
|
|
4
|
+
return {
|
|
5
|
+
key: semanticRef(row.key, `${label}.key`),
|
|
6
|
+
source_path: repositoryFile(row.source_path, `${label}.source_path`),
|
|
7
|
+
sha256: sha256(row.sha256, `${label}.sha256`),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function parseSemanticFactOutcomeBindings(value, label) {
|
|
11
|
+
const row = object(value, label, ["manifest_ref", "facts", "proofs"]);
|
|
12
|
+
return {
|
|
13
|
+
manifest_ref: semanticRef(row.manifest_ref, `${label}.manifest_ref`),
|
|
14
|
+
facts: array(row.facts, `${label}.facts`).map((item, index) => {
|
|
15
|
+
const itemLabel = `${label}.facts[${index}]`;
|
|
16
|
+
const entry = object(item, itemLabel, [
|
|
17
|
+
"fact_ref",
|
|
18
|
+
"claim_ref",
|
|
19
|
+
"applicability_ref",
|
|
20
|
+
]);
|
|
21
|
+
return {
|
|
22
|
+
fact_ref: semanticRef(entry.fact_ref, `${itemLabel}.fact_ref`),
|
|
23
|
+
claim_ref: semanticRef(entry.claim_ref, `${itemLabel}.claim_ref`),
|
|
24
|
+
applicability_ref: semanticRef(entry.applicability_ref, `${itemLabel}.applicability_ref`),
|
|
25
|
+
};
|
|
26
|
+
}),
|
|
27
|
+
proofs: array(row.proofs, `${label}.proofs`).map((item, index) => {
|
|
28
|
+
const itemLabel = `${label}.proofs[${index}]`;
|
|
29
|
+
const preliminary = object(item, itemLabel, [
|
|
30
|
+
"proof_ref",
|
|
31
|
+
"fact_ref",
|
|
32
|
+
"method",
|
|
33
|
+
"proof_surface",
|
|
34
|
+
"evidence_capabilities",
|
|
35
|
+
"authority",
|
|
36
|
+
], ["check_ref", "assertion_ref", "confirmation_ref"]);
|
|
37
|
+
const authority = literal(preliminary.authority, ["machine", "external_confirmation"], `${itemLabel}.authority`);
|
|
38
|
+
if (authority === "machine") {
|
|
39
|
+
requireOwned(preliminary, itemLabel, ["check_ref", "assertion_ref"]);
|
|
40
|
+
forbidOwned(preliminary, itemLabel, ["confirmation_ref"]);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
requireOwned(preliminary, itemLabel, ["confirmation_ref"]);
|
|
44
|
+
forbidOwned(preliminary, itemLabel, ["check_ref", "assertion_ref"]);
|
|
45
|
+
}
|
|
46
|
+
const base = {
|
|
47
|
+
proof_ref: semanticRef(preliminary.proof_ref, `${itemLabel}.proof_ref`),
|
|
48
|
+
fact_ref: semanticRef(preliminary.fact_ref, `${itemLabel}.fact_ref`),
|
|
49
|
+
method: semanticRef(preliminary.method, `${itemLabel}.method`),
|
|
50
|
+
proof_surface: literal(preliminary.proof_surface, PROOF_SURFACES, `${itemLabel}.proof_surface`),
|
|
51
|
+
evidence_capabilities: array(preliminary.evidence_capabilities, `${itemLabel}.evidence_capabilities`).map((capability, capabilityIndex) => literal(capability, EVIDENCE_CAPABILITIES, `${itemLabel}.evidence_capabilities[${capabilityIndex}]`)),
|
|
52
|
+
};
|
|
53
|
+
return authority === "machine"
|
|
54
|
+
? {
|
|
55
|
+
...base,
|
|
56
|
+
authority,
|
|
57
|
+
check_ref: semanticRef(preliminary.check_ref, `${itemLabel}.check_ref`),
|
|
58
|
+
assertion_ref: semanticRef(preliminary.assertion_ref, `${itemLabel}.assertion_ref`),
|
|
59
|
+
}
|
|
60
|
+
: {
|
|
61
|
+
...base,
|
|
62
|
+
authority,
|
|
63
|
+
confirmation_ref: semanticRef(preliminary.confirmation_ref, `${itemLabel}.confirmation_ref`),
|
|
64
|
+
};
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function semanticRef(value, label) {
|
|
69
|
+
const result = string(value, label);
|
|
70
|
+
if (!/^[a-z0-9][a-z0-9._:-]*$/u.test(result))
|
|
71
|
+
fail(label, "must be a stable lowercase semantic reference");
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function sha256(value, label) {
|
|
75
|
+
const result = string(value, label);
|
|
76
|
+
if (!/^[a-f0-9]{64}$/u.test(result))
|
|
77
|
+
fail(label, "must be a lowercase SHA-256 digest");
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
function requireOwned(row, label, fields) {
|
|
81
|
+
const missing = fields.filter((field) => !Object.hasOwn(row, field));
|
|
82
|
+
if (missing.length)
|
|
83
|
+
fail(label, `missing keys: ${missing.join(",")}`);
|
|
84
|
+
}
|
|
85
|
+
function forbidOwned(row, label, fields) {
|
|
86
|
+
const present = fields.filter((field) => Object.hasOwn(row, field));
|
|
87
|
+
if (present.length)
|
|
88
|
+
fail(label, `forbidden keys: ${present.join(",")}`);
|
|
89
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CompiledSourceItemV2 } from "./long-task-source-authority-types.js";
|
|
2
|
+
import type { SemanticFactManifestV1 } from "./semantic-fact-types.js";
|
|
3
|
+
export declare function validateSemanticFactLocatedValues(repository: string, manifest: SemanticFactManifestV1, sourceItems: CompiledSourceItemV2[]): Promise<void>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveSemanticFactPointer, semanticFactClosureInvalid, } from "./long-task-semantic-fact-closure-primitives.js";
|
|
4
|
+
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
5
|
+
import { canonicalValueJson, parseStrictYaml, sha256Hex, } from "./strict-codec.js";
|
|
6
|
+
export async function validateSemanticFactLocatedValues(repository, manifest, sourceItems) {
|
|
7
|
+
const values = collectLocatedValues(manifest);
|
|
8
|
+
const inputs = new Map(manifest.inputs.map((item) => [item.key, item]));
|
|
9
|
+
const sourceItemByKey = new Map(sourceItems.map((item) => [item.key, item]));
|
|
10
|
+
const resourceCache = new Map();
|
|
11
|
+
for (const entry of values) {
|
|
12
|
+
const located = entry.value;
|
|
13
|
+
if (located.representation === "digest_only")
|
|
14
|
+
continue;
|
|
15
|
+
const resolved = await resolveLocatedValue(repository, manifest, entry.label, located, inputs, sourceItemByKey, resourceCache);
|
|
16
|
+
if (resolved.external)
|
|
17
|
+
continue;
|
|
18
|
+
if (located.representation === "inline" &&
|
|
19
|
+
canonicalValueJson(resolved.value) !== canonicalValueJson(located.value))
|
|
20
|
+
semanticFactClosureInvalid("inline_value_locator_mismatch", entry.label);
|
|
21
|
+
const digest = sha256Hex(canonicalValueJson(resolved.value));
|
|
22
|
+
if (digest !== located.sha256)
|
|
23
|
+
semanticFactClosureInvalid("located_value_digest_mismatch", `${entry.label}:${located.sha256}:${digest}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function collectLocatedValues(manifest) {
|
|
27
|
+
return [
|
|
28
|
+
...manifest.populations.map((item) => ({
|
|
29
|
+
label: `population:${item.key}:universe`,
|
|
30
|
+
value: item.universe,
|
|
31
|
+
})),
|
|
32
|
+
...manifest.facts.map((item) => ({
|
|
33
|
+
label: `fact:${item.key}:expected`,
|
|
34
|
+
value: item.expected,
|
|
35
|
+
})),
|
|
36
|
+
...manifest.proof_obligations.flatMap((item) => [
|
|
37
|
+
{
|
|
38
|
+
label: `proof:${item.key}:parameters`,
|
|
39
|
+
value: item.comparison.parameters,
|
|
40
|
+
},
|
|
41
|
+
...(item.comparison.tolerance
|
|
42
|
+
? [
|
|
43
|
+
{
|
|
44
|
+
label: `proof:${item.key}:tolerance`,
|
|
45
|
+
value: item.comparison.tolerance,
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
: []),
|
|
49
|
+
...(item.comparison.mask
|
|
50
|
+
? [
|
|
51
|
+
{
|
|
52
|
+
label: `proof:${item.key}:mask`,
|
|
53
|
+
value: item.comparison.mask,
|
|
54
|
+
},
|
|
55
|
+
]
|
|
56
|
+
: []),
|
|
57
|
+
]),
|
|
58
|
+
...manifest.environments.map((item) => ({
|
|
59
|
+
label: `environment:${item.key}`,
|
|
60
|
+
value: item.definition,
|
|
61
|
+
})),
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
async function resolveLocatedValue(repository, manifest, label, located, inputs, sourceItemByKey, resourceCache) {
|
|
65
|
+
if (located.locator.kind === "manifest_pointer")
|
|
66
|
+
return {
|
|
67
|
+
external: false,
|
|
68
|
+
value: resolveSemanticFactPointer(manifest, located.locator.value, label),
|
|
69
|
+
};
|
|
70
|
+
const input = inputs.get(located.locator.material_ref);
|
|
71
|
+
if (!input)
|
|
72
|
+
semanticFactClosureInvalid("located_value_input_unknown", `${label}:${located.locator.material_ref}`);
|
|
73
|
+
if (located.locator.kind === "source_item") {
|
|
74
|
+
if (input.kind !== "source_item")
|
|
75
|
+
semanticFactClosureInvalid("located_value_source_item_kind_mismatch", label);
|
|
76
|
+
const sourceItem = sourceItemByKey.get(input.source_ref);
|
|
77
|
+
if (!sourceItem)
|
|
78
|
+
semanticFactClosureInvalid("located_value_source_item_unknown", label);
|
|
79
|
+
return { external: false, value: sourceItem.normalized_text };
|
|
80
|
+
}
|
|
81
|
+
const resource = await loadLocatedResource(repository, input.source_ref, label, located.locator.kind, resourceCache);
|
|
82
|
+
if (located.locator.kind === "whole_resource")
|
|
83
|
+
return { external: false, value: resource.raw };
|
|
84
|
+
if (located.locator.kind === "json_pointer" ||
|
|
85
|
+
located.locator.kind === "yaml_pointer" ||
|
|
86
|
+
located.locator.kind === "schema_pointer")
|
|
87
|
+
return {
|
|
88
|
+
external: false,
|
|
89
|
+
value: resolveSemanticFactPointer(resource.parsed, located.locator.value, label),
|
|
90
|
+
};
|
|
91
|
+
if (manifest.inspector.trust !== "named_external_tcb" ||
|
|
92
|
+
!manifest.inspector.capabilities.includes(`resolve.${located.locator.kind}`))
|
|
93
|
+
semanticFactClosureInvalid("located_value_external_resolver_required", `${label}:${located.locator.kind}`);
|
|
94
|
+
return { external: true, value: undefined };
|
|
95
|
+
}
|
|
96
|
+
async function loadLocatedResource(repository, sourceRef, label, locatorKind, cache) {
|
|
97
|
+
const cached = cache.get(sourceRef);
|
|
98
|
+
if (cached)
|
|
99
|
+
return cached;
|
|
100
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...sourceRef.split("/")), `semantic_fact_located_value:${label}`);
|
|
101
|
+
const raw = await readFile(file, "utf8");
|
|
102
|
+
let parsed = raw;
|
|
103
|
+
if (locatorKind === "json_pointer" || locatorKind === "schema_pointer")
|
|
104
|
+
parsed = JSON.parse(raw);
|
|
105
|
+
else if (locatorKind === "yaml_pointer")
|
|
106
|
+
parsed = parseStrictYaml(raw);
|
|
107
|
+
const resource = { raw, parsed };
|
|
108
|
+
cache.set(sourceRef, resource);
|
|
109
|
+
return resource;
|
|
110
|
+
}
|
|
@@ -13,8 +13,9 @@ export declare function repositoryCwd(value: unknown, label: string): string;
|
|
|
13
13
|
export declare function repositorySourceRef(value: unknown, label: string): string;
|
|
14
14
|
export declare function literal<T extends string>(value: unknown, allowed: readonly T[], label: string): T;
|
|
15
15
|
export declare function key(value: unknown, label: string): string;
|
|
16
|
+
export declare function semanticRef(value: unknown, label: string): string;
|
|
16
17
|
export declare function nullable<T>(value: unknown, parser: (value: unknown) => T): T | null;
|
|
17
18
|
export declare const PROOF_SURFACES: readonly ["ui_browser", "runtime_behavior", "api_contract", "data_state", "security_boundary", "population_coverage", "implementation_structure"];
|
|
18
19
|
export declare const JOURNEY_ROLES: readonly ["success", "degradation", "recovery", "stage_gate", "conformance"];
|
|
19
|
-
export declare const EVIDENCE_CAPABILITIES: readonly ["presence", "interaction_trace", "state_delta", "cross_surface_consistency", "durable_readback", "boundary_invocation", "external_side_effect", "failure_injection", "visual_render", "design_conformance", "design_method", "target_runtime", "input_variation"];
|
|
20
|
+
export declare const EVIDENCE_CAPABILITIES: readonly ["presence", "interaction_trace", "state_delta", "cross_surface_consistency", "durable_readback", "boundary_invocation", "external_side_effect", "failure_injection", "visual_render", "design_conformance", "design_method", "semantic_fact", "target_runtime", "input_variation"];
|
|
20
21
|
export declare function fail(label: string, message: string): never;
|