project-tiny-context-harness 0.7.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +393 -380
- package/assets/README.md +567 -557
- package/assets/README.zh-CN.md +339 -326
- package/assets/agents/.gitkeep +1 -1
- package/assets/agents/AGENTS_CORE.md +66 -64
- package/assets/context_templates/architecture.md +33 -33
- package/assets/context_templates/area.md +39 -39
- package/assets/context_templates/context.toml +30 -30
- package/assets/context_templates/deployment.md +35 -35
- package/assets/context_templates/global.md +52 -51
- package/assets/context_templates/product-surface-contract.md +70 -70
- package/assets/context_templates/screen-contract.md +186 -177
- package/assets/context_templates/verification.md +32 -32
- package/assets/github/.gitkeep +1 -1
- package/assets/github/harness.yml +41 -41
- package/assets/make/.gitkeep +1 -1
- package/assets/make/ty-context.mk +48 -48
- package/assets/skills/context_development_engineer/SKILL.md +135 -131
- package/assets/skills/context_full_project_export/SKILL.md +70 -70
- package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
- package/assets/skills/context_product_plan/SKILL.md +88 -87
- package/assets/skills/context_surface_contract/SKILL.md +191 -191
- package/assets/skills/context_uiux_design/SKILL.md +158 -154
- package/assets/skills/design-resource-authoring/SKILL.md +84 -79
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +136 -108
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +133 -127
- package/assets/skills/design-resource-authoring/references/resource-selection.md +173 -173
- 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 -47
- package/assets/skills/design-system-authoring/references/open-design-design-system-provider.md +110 -110
- package/assets/skills/long-task-workflow/SKILL.md +100 -92
- package/assets/skills/long-task-workflow/agents/openai.yaml +4 -4
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +76 -59
- package/assets/skills/long-task-workflow/references/contract-authoring.md +116 -105
- package/assets/skills/long-task-workflow/references/evidence-design.md +78 -75
- package/assets/skills/long-task-workflow/references/source-authoring.md +101 -98
- package/assets/skills/normal-long-task/SKILL.md +12 -12
- package/assets/skills/source-plan-authoring/SKILL.md +14 -14
- package/assets/tools/validate_context.py +442 -442
- package/dist/commands/design-resource.d.ts +1 -0
- package/dist/commands/design-resource.js +32 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/long-task-command-args.d.ts +1 -0
- package/dist/commands/long-task-command-args.js +6 -0
- package/dist/commands/long-task-revision.js +16 -4
- package/dist/commands/long-task.js +12 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/design-md.js +3 -1
- package/dist/lib/design-resource-handoff-file-primitives.d.ts +4 -0
- package/dist/lib/design-resource-handoff-file-primitives.js +14 -0
- package/dist/lib/design-resource-handoff-file-validation.d.ts +2 -0
- package/dist/lib/design-resource-handoff-file-validation.js +142 -0
- package/dist/lib/design-resource-handoff-parser.d.ts +3 -0
- package/dist/lib/design-resource-handoff-parser.js +29 -0
- package/dist/lib/design-resource-handoff-policy.d.ts +3 -0
- package/dist/lib/design-resource-handoff-policy.js +36 -0
- package/dist/lib/design-resource-handoff-shape-evidence.d.ts +4 -0
- package/dist/lib/design-resource-handoff-shape-evidence.js +84 -0
- package/dist/lib/design-resource-handoff-shape-primitives.d.ts +9 -0
- package/dist/lib/design-resource-handoff-shape-primitives.js +44 -0
- package/dist/lib/design-resource-handoff-shape-structure.d.ts +5 -0
- package/dist/lib/design-resource-handoff-shape-structure.js +118 -0
- package/dist/lib/design-resource-handoff-shape.d.ts +2 -0
- package/dist/lib/design-resource-handoff-shape.js +75 -0
- package/dist/lib/design-resource-handoff-types.d.ts +139 -0
- package/dist/lib/design-resource-handoff-types.js +46 -0
- package/dist/lib/design-resource-handoff-validation-coverage.d.ts +4 -0
- package/dist/lib/design-resource-handoff-validation-coverage.js +168 -0
- package/dist/lib/design-resource-handoff-validation-primitives.d.ts +11 -0
- package/dist/lib/design-resource-handoff-validation-primitives.js +26 -0
- package/dist/lib/design-resource-handoff-validation-structure.d.ts +6 -0
- package/dist/lib/design-resource-handoff-validation-structure.js +93 -0
- package/dist/lib/design-resource-handoff-validation.d.ts +3 -0
- package/dist/lib/design-resource-handoff-validation.js +78 -0
- package/dist/lib/design-resource-handoff-web-dependency-validation.d.ts +3 -0
- package/dist/lib/design-resource-handoff-web-dependency-validation.js +70 -0
- package/dist/lib/long-task-activation-validation.js +14 -2
- package/dist/lib/long-task-authoring-preflight-diagnostics.js +7 -0
- package/dist/lib/long-task-authoring-preflight.js +39 -1
- package/dist/lib/long-task-authority-material-diff.js +14 -0
- package/dist/lib/long-task-authority-materials.js +21 -0
- package/dist/lib/long-task-authority-policy.d.ts +33 -0
- package/dist/lib/long-task-authority-policy.js +36 -0
- package/dist/lib/long-task-authority-revision-analysis.d.ts +1 -0
- package/dist/lib/long-task-authority-revision-analysis.js +30 -0
- package/dist/lib/long-task-authority-revision-brief.d.ts +3 -0
- package/dist/lib/long-task-authority-revision-brief.js +74 -0
- package/dist/lib/long-task-authority-revision-details.js +16 -16
- package/dist/lib/long-task-authority-revision-diagnosis.d.ts +1 -1
- package/dist/lib/long-task-authority-revision-diagnosis.js +8 -0
- package/dist/lib/long-task-authority-revision-enforcement.js +7 -3
- package/dist/lib/long-task-authority-revision-summary.d.ts +3 -0
- package/dist/lib/long-task-authority-revision-summary.js +133 -21
- package/dist/lib/long-task-authority-revision-types.d.ts +19 -1
- package/dist/lib/long-task-authority-revision.js +5 -0
- package/dist/lib/long-task-authority-types.d.ts +2 -0
- package/dist/lib/long-task-authority.js +10 -2
- package/dist/lib/long-task-check-execution-policy.js +2 -0
- package/dist/lib/long-task-claim-definitions.js +1 -5
- package/dist/lib/long-task-contract-types.d.ts +2 -0
- package/dist/lib/long-task-counterfactual-sandbox.d.ts +7 -0
- package/dist/lib/long-task-counterfactual-sandbox.js +27 -1
- package/dist/lib/long-task-delivery-compiler.js +26 -8
- 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 +3 -0
- package/dist/lib/long-task-design-resource-handoff.d.ts +2 -0
- package/dist/lib/long-task-design-resource-handoff.js +177 -0
- package/dist/lib/long-task-evidence-capability-codec.js +19 -0
- package/dist/lib/long-task-evidence-capability-policy.js +4 -0
- package/dist/lib/long-task-evidence-capability-runtime.js +25 -0
- package/dist/lib/long-task-evidence-capability-types.d.ts +9 -1
- package/dist/lib/long-task-outcome-parser.js +11 -1
- package/dist/lib/long-task-paths.d.ts +0 -1
- package/dist/lib/long-task-paths.js +0 -4
- package/dist/lib/long-task-playwright-case-evidence.d.ts +43 -0
- package/dist/lib/long-task-playwright-case-evidence.js +152 -0
- package/dist/lib/long-task-playwright-evidence.js +19 -152
- package/dist/lib/long-task-runner-freeze.d.ts +2 -2
- package/dist/lib/long-task-runner-freeze.js +2 -1
- package/dist/lib/long-task-runtime-types.d.ts +2 -0
- package/dist/lib/long-task-semantic-contract-types.d.ts +1 -1
- package/dist/lib/long-task-semantic-drift-migration.js +6 -1
- 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-status-v2.js +12 -7
- package/dist/lib/long-task-ui-design-policy.d.ts +17 -0
- package/dist/lib/long-task-ui-design-policy.js +128 -0
- package/dist/lib/long-task-ui-surface-policy.d.ts +4 -0
- package/dist/lib/long-task-ui-surface-policy.js +109 -0
- package/dist/lib/long-task-ui-surface-shape.d.ts +2 -0
- package/dist/lib/long-task-ui-surface-shape.js +94 -0
- package/dist/lib/long-task-ui-surface-types.d.ts +44 -0
- package/dist/lib/long-task-ui-surface-types.js +1 -0
- package/dist/lib/long-task-ui-surface-validation.d.ts +11 -0
- package/dist/lib/long-task-ui-surface-validation.js +62 -0
- package/dist/lib/long-task-verification-preview.d.ts +55 -0
- package/dist/lib/long-task-verification-preview.js +120 -0
- package/dist/lib/long-task-verifier-v2.js +11 -18
- package/dist/lib/long-task-workspace-scope.d.ts +38 -0
- package/dist/lib/long-task-workspace-scope.js +121 -0
- package/dist/lib/long-task-workspace.d.ts +1 -0
- package/dist/lib/long-task-workspace.js +73 -9
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +84 -2
- package/migrations/README.md +7 -7
- package/package.json +3 -3
- package/source-mappings.yaml +25 -25
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { invalidDesignResourceHandoff, requireKnownDesignResourceRef, requireNonemptyDesignResourceValues, requireUniqueDesignResourceValues, } from "./design-resource-handoff-validation-primitives.js";
|
|
2
|
+
export function validateDesignResourceScope(handoff) {
|
|
3
|
+
const surfaceStableKeys = new Set(handoff.subjects
|
|
4
|
+
.filter((subject) => subject.kind === "surface")
|
|
5
|
+
.flatMap((subject) => subject.stable_keys));
|
|
6
|
+
for (const surfaceKey of handoff.scope.surface_keys)
|
|
7
|
+
if (!surfaceStableKeys.has(surfaceKey))
|
|
8
|
+
invalidDesignResourceHandoff("scope_surface_subject_missing", surfaceKey);
|
|
9
|
+
}
|
|
10
|
+
export function validateDesignResourceConditions(handoff) {
|
|
11
|
+
for (const condition of handoff.conditions) {
|
|
12
|
+
for (const [name, values] of [
|
|
13
|
+
["modes", condition.modes],
|
|
14
|
+
["states", condition.states],
|
|
15
|
+
["content_cases", condition.content_cases],
|
|
16
|
+
["input_methods", condition.input_methods],
|
|
17
|
+
]) {
|
|
18
|
+
requireNonemptyDesignResourceValues(values, `condition_${name}_required:${condition.key}`);
|
|
19
|
+
requireUniqueDesignResourceValues(values, `condition_${name}_duplicate:${condition.key}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function validateDesignResourceSubjects(handoff, targets) {
|
|
24
|
+
const stableKeys = new Set();
|
|
25
|
+
for (const subject of handoff.subjects) {
|
|
26
|
+
requireNonemptyDesignResourceValues(subject.stable_keys, `subject_stable_keys_required:${subject.key}`);
|
|
27
|
+
requireUniqueDesignResourceValues(subject.stable_keys, `subject_stable_key_duplicate:${subject.key}`);
|
|
28
|
+
requireNonemptyDesignResourceValues(subject.target_refs, `subject_target_refs_required:${subject.key}`);
|
|
29
|
+
requireUniqueDesignResourceValues(subject.target_refs, `subject_target_ref_duplicate:${subject.key}`);
|
|
30
|
+
for (const ref of subject.target_refs)
|
|
31
|
+
requireKnownDesignResourceRef(targets, ref, "target");
|
|
32
|
+
for (const stableKey of subject.stable_keys) {
|
|
33
|
+
if (stableKeys.has(stableKey))
|
|
34
|
+
invalidDesignResourceHandoff("subject_stable_key_ambiguous", stableKey);
|
|
35
|
+
stableKeys.add(stableKey);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function validateDesignResourceTargets(handoff, resources, conditions) {
|
|
40
|
+
for (const target of handoff.targets) {
|
|
41
|
+
requireNonemptyDesignResourceValues(target.resource_refs, `target_resource_refs_required:${target.key}`);
|
|
42
|
+
requireNonemptyDesignResourceValues(target.condition_refs, `target_condition_refs_required:${target.key}`);
|
|
43
|
+
requireUniqueDesignResourceValues(target.resource_refs, `target_resource_ref_duplicate:${target.key}`);
|
|
44
|
+
requireUniqueDesignResourceValues(target.condition_refs, `target_condition_ref_duplicate:${target.key}`);
|
|
45
|
+
for (const ref of target.resource_refs)
|
|
46
|
+
requireKnownDesignResourceRef(resources, ref, "resource");
|
|
47
|
+
for (const ref of target.condition_refs)
|
|
48
|
+
requireKnownDesignResourceRef(conditions, ref, "condition");
|
|
49
|
+
validateTargetSourceProfile(target, resources);
|
|
50
|
+
const expectedRole = target.interpretation === "exact_target" ? "exact_target" : "constraint";
|
|
51
|
+
if (!target.resource_refs.some((ref) => resources.get(ref)?.role === expectedRole))
|
|
52
|
+
invalidDesignResourceHandoff("target_interpretation_resource_role_missing", `${target.key}:${expectedRole}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function validateTargetSourceProfile(target, resources) {
|
|
56
|
+
const profile = target.source_profile;
|
|
57
|
+
requireKnownDesignResourceRef(resources, profile.entry_resource_ref, "source_profile_entry_resource");
|
|
58
|
+
requireUniqueDesignResourceValues(profile.dependency_resource_refs, `source_profile_dependency_resource_ref_duplicate:${target.key}`);
|
|
59
|
+
for (const ref of profile.dependency_resource_refs)
|
|
60
|
+
requireKnownDesignResourceRef(resources, ref, "source_profile_dependency_resource");
|
|
61
|
+
if (profile.dependency_resource_refs.includes(profile.entry_resource_ref))
|
|
62
|
+
invalidDesignResourceHandoff("source_profile_entry_repeated_as_dependency", target.key);
|
|
63
|
+
const declared = [
|
|
64
|
+
profile.entry_resource_ref,
|
|
65
|
+
...profile.dependency_resource_refs,
|
|
66
|
+
].sort();
|
|
67
|
+
const targetResources = [...target.resource_refs].sort();
|
|
68
|
+
if (declared.length !== targetResources.length ||
|
|
69
|
+
declared.some((ref, index) => ref !== targetResources[index]))
|
|
70
|
+
invalidDesignResourceHandoff("source_profile_resource_closure_mismatch", target.key);
|
|
71
|
+
const entry = resources.get(profile.entry_resource_ref);
|
|
72
|
+
if (profile.kind === "implementation_web" &&
|
|
73
|
+
!["text/html", "application/xhtml+xml"].includes(entry.media_type))
|
|
74
|
+
invalidDesignResourceHandoff("implementation_web_entry_media_type_invalid", `${target.key}:${entry.media_type}`);
|
|
75
|
+
if (profile.kind === "implementation_app" &&
|
|
76
|
+
!(entry.media_type.startsWith("text/") ||
|
|
77
|
+
[
|
|
78
|
+
"application/json",
|
|
79
|
+
"application/javascript",
|
|
80
|
+
"application/yaml",
|
|
81
|
+
"application/x-yaml",
|
|
82
|
+
].includes(entry.media_type)))
|
|
83
|
+
invalidDesignResourceHandoff("implementation_app_entry_media_type_invalid", `${target.key}:${entry.media_type}`);
|
|
84
|
+
}
|
|
85
|
+
export function validateDesignResourceEvidence(handoff, resources, conditions) {
|
|
86
|
+
for (const item of handoff.evidence) {
|
|
87
|
+
requireKnownDesignResourceRef(resources, item.resource_ref, "resource");
|
|
88
|
+
requireNonemptyDesignResourceValues(item.condition_refs, `evidence_condition_refs_required:${item.key}`);
|
|
89
|
+
requireUniqueDesignResourceValues(item.condition_refs, `evidence_condition_ref_duplicate:${item.key}`);
|
|
90
|
+
for (const ref of item.condition_refs)
|
|
91
|
+
requireKnownDesignResourceRef(conditions, ref, "condition");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DesignResourceHandoffPreflightV1, ParsedDesignResourceHandoffV1 } from "./design-resource-handoff-types.js";
|
|
2
|
+
export declare function preflightDesignResourceHandoff(repository: string, handoffPath: string): Promise<DesignResourceHandoffPreflightV1>;
|
|
3
|
+
export declare function validateDesignResourceHandoffSemantics(parsed: ParsedDesignResourceHandoffV1): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseDesignResourceHandoffMarkdown } from "./design-resource-handoff-parser.js";
|
|
4
|
+
import { validateDesignResourceFiles } from "./design-resource-handoff-file-validation.js";
|
|
5
|
+
import { validateDesignResourceBlockers, validateDesignResourceCoverage, validateDesignResourceReachability, } from "./design-resource-handoff-validation-coverage.js";
|
|
6
|
+
import { indexDesignResourceItems, invalidDesignResourceHandoff, requireNonemptyDesignResourceValues, requireUniqueDesignResourceObjects, requireUniqueDesignResourceValues, } from "./design-resource-handoff-validation-primitives.js";
|
|
7
|
+
import { validateDesignResourceConditions, validateDesignResourceEvidence, validateDesignResourceScope, validateDesignResourceSubjects, validateDesignResourceTargets, } from "./design-resource-handoff-validation-structure.js";
|
|
8
|
+
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
9
|
+
import { sha256Hex } from "./strict-codec.js";
|
|
10
|
+
export async function preflightDesignResourceHandoff(repository, handoffPath) {
|
|
11
|
+
const handoffFile = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...handoffPath.split("/")), "design_resource_handoff");
|
|
12
|
+
const parsed = parseDesignResourceHandoffMarkdown(handoffPath, await readFile(handoffFile, "utf8"));
|
|
13
|
+
validateDesignResourceHandoffSemantics(parsed);
|
|
14
|
+
const resourceHashes = await validateResourceIntegrity(repository, parsed);
|
|
15
|
+
await validateDesignResourceFiles(repository, parsed);
|
|
16
|
+
const handoff = parsed.handoff;
|
|
17
|
+
return {
|
|
18
|
+
schema_version: "design-resource-handoff-preflight-v1",
|
|
19
|
+
status: "ready",
|
|
20
|
+
...parsed,
|
|
21
|
+
resource_hashes: resourceHashes,
|
|
22
|
+
counts: {
|
|
23
|
+
resources: handoff.resources.length,
|
|
24
|
+
conditions: handoff.conditions.length,
|
|
25
|
+
subjects: handoff.subjects.length,
|
|
26
|
+
targets: handoff.targets.length,
|
|
27
|
+
evidence: handoff.evidence.length,
|
|
28
|
+
coverage: handoff.coverage.length,
|
|
29
|
+
acceptance_blockers: handoff.acceptance_blockers.length,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function validateDesignResourceHandoffSemantics(parsed) {
|
|
34
|
+
const { handoff } = parsed;
|
|
35
|
+
requireNonemptyDesignResourceValues(handoff.scope.surface_keys, "scope_surface_keys_required");
|
|
36
|
+
requireNonemptyDesignResourceValues(handoff.resources, "resources_required");
|
|
37
|
+
requireNonemptyDesignResourceValues(handoff.conditions, "conditions_required");
|
|
38
|
+
requireNonemptyDesignResourceValues(handoff.subjects, "subjects_required");
|
|
39
|
+
requireNonemptyDesignResourceValues(handoff.targets, "targets_required");
|
|
40
|
+
requireNonemptyDesignResourceValues(handoff.evidence, "evidence_required");
|
|
41
|
+
requireNonemptyDesignResourceValues(handoff.coverage, "coverage_required");
|
|
42
|
+
requireUniqueDesignResourceValues(handoff.scope.surface_keys, "scope_surface_key_duplicate");
|
|
43
|
+
requireUniqueDesignResourceObjects(handoff.resources, "resource_key_duplicate");
|
|
44
|
+
requireUniqueDesignResourceValues(handoff.resources.map((item) => item.path), "resource_path_duplicate");
|
|
45
|
+
requireUniqueDesignResourceObjects(handoff.conditions, "condition_key_duplicate");
|
|
46
|
+
requireUniqueDesignResourceObjects(handoff.subjects, "subject_key_duplicate");
|
|
47
|
+
requireUniqueDesignResourceObjects(handoff.targets, "target_key_duplicate");
|
|
48
|
+
requireUniqueDesignResourceObjects(handoff.evidence, "evidence_key_duplicate");
|
|
49
|
+
requireUniqueDesignResourceObjects(handoff.coverage, "coverage_key_duplicate");
|
|
50
|
+
requireUniqueDesignResourceObjects(handoff.acceptance_blockers, "acceptance_blocker_key_duplicate");
|
|
51
|
+
const resources = indexDesignResourceItems(handoff.resources);
|
|
52
|
+
const conditions = indexDesignResourceItems(handoff.conditions);
|
|
53
|
+
const subjects = indexDesignResourceItems(handoff.subjects);
|
|
54
|
+
const targets = indexDesignResourceItems(handoff.targets);
|
|
55
|
+
const evidence = indexDesignResourceItems(handoff.evidence);
|
|
56
|
+
const sourceItems = new Map(Object.entries(parsed.source_item_kinds));
|
|
57
|
+
validateDesignResourceScope(handoff);
|
|
58
|
+
validateDesignResourceConditions(handoff);
|
|
59
|
+
validateDesignResourceSubjects(handoff, targets);
|
|
60
|
+
validateDesignResourceTargets(handoff, resources, conditions);
|
|
61
|
+
validateDesignResourceEvidence(handoff, resources, conditions);
|
|
62
|
+
validateDesignResourceCoverage(handoff, subjects, targets, conditions, evidence, sourceItems);
|
|
63
|
+
validateDesignResourceBlockers(handoff, subjects, targets, sourceItems);
|
|
64
|
+
validateDesignResourceReachability(handoff);
|
|
65
|
+
}
|
|
66
|
+
async function validateResourceIntegrity(repository, parsed) {
|
|
67
|
+
const hashes = {};
|
|
68
|
+
for (const resource of parsed.handoff.resources) {
|
|
69
|
+
if (resource.path === parsed.handoff_path)
|
|
70
|
+
invalidDesignResourceHandoff("resource_must_not_be_handoff", resource.key);
|
|
71
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...resource.path.split("/")), `design_resource:${resource.key}`);
|
|
72
|
+
const digest = sha256Hex(await readFile(file));
|
|
73
|
+
if (digest !== resource.sha256)
|
|
74
|
+
invalidDesignResourceHandoff("resource_digest_mismatch", `${resource.key}:${resource.sha256}:${digest}`);
|
|
75
|
+
hashes[resource.key] = digest;
|
|
76
|
+
}
|
|
77
|
+
return hashes;
|
|
78
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ParsedDesignResourceHandoffV1 } from "./design-resource-handoff-types.js";
|
|
2
|
+
import { type DesignResource } from "./design-resource-handoff-file-primitives.js";
|
|
3
|
+
export declare function validateDesignResourceWebDependencyClosure(target: ParsedDesignResourceHandoffV1["handoff"]["targets"][number], resources: Map<string, DesignResource>, contents: Map<string, Buffer>): void;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { htmlAttributes, isTextResource, } from "./design-resource-handoff-file-primitives.js";
|
|
3
|
+
import { invalidDesignResourceHandoff } from "./design-resource-handoff-validation-primitives.js";
|
|
4
|
+
export function validateDesignResourceWebDependencyClosure(target, resources, contents) {
|
|
5
|
+
const declaredPaths = new Set(target.resource_refs.map((ref) => resources.get(ref).path));
|
|
6
|
+
for (const resourceRef of target.resource_refs) {
|
|
7
|
+
const resource = resources.get(resourceRef);
|
|
8
|
+
if (!isTextResource(resource))
|
|
9
|
+
continue;
|
|
10
|
+
const content = contents.get(resourceRef).toString("utf8");
|
|
11
|
+
for (const reference of localDependencyReferences(content, resource.media_type)) {
|
|
12
|
+
const resolved = resolveResourceReference(resource.path, reference);
|
|
13
|
+
if (!declaredPaths.has(resolved))
|
|
14
|
+
invalidDesignResourceHandoff("implementation_dependency_undeclared", `${target.key}:${resource.path}:${reference}:${resolved}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function localDependencyReferences(content, mediaType) {
|
|
19
|
+
const values = new Set();
|
|
20
|
+
if (["text/html", "application/xhtml+xml"].includes(mediaType)) {
|
|
21
|
+
for (const tag of content.matchAll(/<(script|img|source|video|audio|track|iframe|embed|input|link|object|use|image)\b([^<>]*)>/giu)) {
|
|
22
|
+
const attributes = htmlAttributes(tag[2]);
|
|
23
|
+
for (const name of ["src", "href", "poster"])
|
|
24
|
+
addLocalReference(values, attributes.get(name));
|
|
25
|
+
if (tag[1].toLowerCase() === "object")
|
|
26
|
+
addLocalReference(values, attributes.get("data"));
|
|
27
|
+
for (const candidate of (attributes.get("srcset") ?? "").split(","))
|
|
28
|
+
addLocalReference(values, candidate.trim().split(/\s+/u)[0]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (mediaType === "text/css" ||
|
|
32
|
+
["text/html", "application/xhtml+xml"].includes(mediaType))
|
|
33
|
+
for (const match of content.matchAll(/(?:url\(\s*["']?([^"')\s]+)|@import\s+(?:url\(\s*)?["']([^"']+))/giu))
|
|
34
|
+
addLocalReference(values, match[1] ?? match[2]);
|
|
35
|
+
if ([
|
|
36
|
+
"text/javascript",
|
|
37
|
+
"application/javascript",
|
|
38
|
+
"text/typescript",
|
|
39
|
+
"application/typescript",
|
|
40
|
+
"text/ecmascript",
|
|
41
|
+
"application/ecmascript",
|
|
42
|
+
"text/html",
|
|
43
|
+
].includes(mediaType)) {
|
|
44
|
+
for (const match of content.matchAll(/(?:\b(?:from|import)\s*|\bimport\s*\(|\brequire\s*\()\s*["']([^"']+)["']/gu))
|
|
45
|
+
addLocalReference(values, match[1]);
|
|
46
|
+
for (const match of content.matchAll(/(?:\bfetch\s*\(|\bnew\s+(?:Shared)?Worker\s*\(|\bnew\s+URL\s*\()\s*["']([^"']+)["']/gu))
|
|
47
|
+
addLocalReference(values, match[1]);
|
|
48
|
+
}
|
|
49
|
+
return values;
|
|
50
|
+
}
|
|
51
|
+
function addLocalReference(values, raw) {
|
|
52
|
+
if (!raw)
|
|
53
|
+
return;
|
|
54
|
+
const value = raw.trim();
|
|
55
|
+
if (!value ||
|
|
56
|
+
value.startsWith("#") ||
|
|
57
|
+
/^(?:[a-z][a-z0-9+.-]*:|\/\/)/iu.test(value))
|
|
58
|
+
return;
|
|
59
|
+
values.add(value.replace(/[?#].*$/u, ""));
|
|
60
|
+
}
|
|
61
|
+
function resolveResourceReference(from, reference) {
|
|
62
|
+
if (reference.startsWith("/"))
|
|
63
|
+
invalidDesignResourceHandoff("implementation_dependency_path_unsafe", `${from}:${reference}`);
|
|
64
|
+
const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(from), reference));
|
|
65
|
+
if (resolved === ".." ||
|
|
66
|
+
resolved.startsWith("../") ||
|
|
67
|
+
path.posix.isAbsolute(resolved))
|
|
68
|
+
invalidDesignResourceHandoff("implementation_dependency_path_unsafe", `${from}:${reference}`);
|
|
69
|
+
return resolved;
|
|
70
|
+
}
|
|
@@ -6,6 +6,7 @@ import { validateClaimEvidenceSensitivity } from "./long-task-evidence-sensitivi
|
|
|
6
6
|
import { validateSemanticConformance } from "./long-task-conformance-policy.js";
|
|
7
7
|
import { deliveryContractStructureDiagnostics, validateDeliveryContractStructure, } from "./long-task-delivery-validation.js";
|
|
8
8
|
import { validateRawExecutionObservationOwnership } from "./long-task-observation-ownership.js";
|
|
9
|
+
import { validateLongTaskDesignResourceHandoffs } from "./long-task-design-resource-handoff.js";
|
|
9
10
|
import { freezeDeliveryCheck } from "./long-task-runner-freeze.js";
|
|
10
11
|
import { classifyLongTaskRisk, validateRiskProof, } from "./long-task-risk.js";
|
|
11
12
|
import { validateSourceContinuity } from "./long-task-source-continuity.js";
|
|
@@ -41,6 +42,7 @@ export async function validateContractForActivation(options) {
|
|
|
41
42
|
: undefined);
|
|
42
43
|
return items;
|
|
43
44
|
});
|
|
45
|
+
await attempt(mode, diagnostics, () => validateLongTaskDesignResourceHandoffs(contract, repository));
|
|
44
46
|
const risk = await attempt(mode, diagnostics, () => {
|
|
45
47
|
const decision = classifyLongTaskRisk(contract);
|
|
46
48
|
validateRiskProof(contract, decision);
|
|
@@ -60,7 +62,7 @@ export async function validateContractForActivation(options) {
|
|
|
60
62
|
const executionTarget = contract.task.execution_targets.find((target) => target.key === check.execution_target.target_ref);
|
|
61
63
|
if (!executionTarget)
|
|
62
64
|
continue;
|
|
63
|
-
const frozen = await attempt(mode, diagnostics, () => freezeDeliveryCheck(check, null, repository, workspace, executionTarget, contract.task.execution_targets), null, check.key);
|
|
65
|
+
const frozen = await attempt(mode, diagnostics, () => freezeDeliveryCheck(check, null, repository, workspace, executionTarget, contract.task.execution_targets, []), null, check.key);
|
|
64
66
|
if (frozen)
|
|
65
67
|
globalChecks.push(frozen);
|
|
66
68
|
}
|
|
@@ -71,7 +73,7 @@ export async function validateContractForActivation(options) {
|
|
|
71
73
|
const executionTarget = contract.task.execution_targets.find((target) => target.key === check.execution_target.target_ref);
|
|
72
74
|
if (!executionTarget)
|
|
73
75
|
continue;
|
|
74
|
-
const frozen = await attempt(mode, diagnostics, () => freezeDeliveryCheck(check, outcome.key, repository, workspace, executionTarget, contract.task.execution_targets), outcome.key, check.key);
|
|
76
|
+
const frozen = await attempt(mode, diagnostics, () => freezeDeliveryCheck(check, outcome.key, repository, workspace, executionTarget, contract.task.execution_targets, designTargetsForCheck(outcome, check.key)), outcome.key, check.key);
|
|
75
77
|
if (frozen)
|
|
76
78
|
checks.push(frozen);
|
|
77
79
|
}
|
|
@@ -114,6 +116,16 @@ export async function validateContractForActivation(options) {
|
|
|
114
116
|
outcomes,
|
|
115
117
|
};
|
|
116
118
|
}
|
|
119
|
+
function designTargetsForCheck(outcome, checkKey) {
|
|
120
|
+
return (outcome.product.surface_bindings ?? []).flatMap((binding) => binding.design_targets
|
|
121
|
+
.filter((target) => target.conformance_check_ref === checkKey)
|
|
122
|
+
.map((target) => ({
|
|
123
|
+
...target,
|
|
124
|
+
surface_binding_ref: binding.key,
|
|
125
|
+
surface_ref: binding.surface_ref,
|
|
126
|
+
target_ref: binding.target_ref,
|
|
127
|
+
})));
|
|
128
|
+
}
|
|
117
129
|
async function attempt(mode, diagnostics, action, outcomeKey, checkKey) {
|
|
118
130
|
try {
|
|
119
131
|
return await action();
|
|
@@ -140,6 +140,9 @@ function diagnosticRefs(code, message) {
|
|
|
140
140
|
return payload.slice(0, 2);
|
|
141
141
|
case "owner_path_globs_empty":
|
|
142
142
|
return payload.slice(0, 1);
|
|
143
|
+
case "workspace_path_forbidden":
|
|
144
|
+
case "workspace_path_unclassified":
|
|
145
|
+
return payload.slice(0, 1);
|
|
143
146
|
case "product_claim_uncovered":
|
|
144
147
|
case "global_claim_uncovered":
|
|
145
148
|
case "source_claim_decision_required":
|
|
@@ -171,6 +174,10 @@ function diagnosticRepairHint(code) {
|
|
|
171
174
|
return "Correct source_ref or add the matching non-rendering Source marker/anchor without rewriting the Source statement.";
|
|
172
175
|
case "source_claim_decision_required":
|
|
173
176
|
return "Resolve the stated product decision from the user or authoritative Source before Compile.";
|
|
177
|
+
case "workspace_path_forbidden":
|
|
178
|
+
return "Revert or relocate the forbidden workspace change, or revise the owning Source/Contract boundary through the appropriate authority path.";
|
|
179
|
+
case "workspace_path_unclassified":
|
|
180
|
+
return "Declare the file under the owning Outcome's expected_change_paths or allowed_support_paths, or remove the unrelated workspace change before Compile.";
|
|
174
181
|
default:
|
|
175
182
|
if (code.endsWith("_path_not_found"))
|
|
176
183
|
return "Create or correct the declared repository path, runner target or Binding carrier, then rerun Preflight.";
|
|
@@ -4,7 +4,8 @@ import { addAuthoringDiagnostics, addDiagnosticError, normalizeAuthoringDiagnost
|
|
|
4
4
|
import { emptyClaimCoverage, emptyPreflightResult, } from "./long-task-authoring-preflight-types.js";
|
|
5
5
|
import { validateContractForActivation } from "./long-task-activation-validation.js";
|
|
6
6
|
import { parseDeliveryContractBundle } from "./long-task-delivery-parser.js";
|
|
7
|
-
import { repositoryRoot } from "./long-task-workspace.js";
|
|
7
|
+
import { changedWorkspacePaths, changedWorkspacePathsFromHead, repoRelative, repositoryRoot, } from "./long-task-workspace.js";
|
|
8
|
+
import { classifyWorkspaceScope, firstLockManagedWorkspacePaths, protectedWorkspacePaths, workspaceScopeErrors, } from "./long-task-workspace-scope.js";
|
|
8
9
|
export async function preflightDeliveryContract(workdirInput, projectRootInput = process.cwd()) {
|
|
9
10
|
const diagnostics = [];
|
|
10
11
|
const repository = await repositoryRoot(projectRootInput);
|
|
@@ -29,6 +30,43 @@ export async function preflightDeliveryContract(workdirInput, projectRootInput =
|
|
|
29
30
|
diagnostics,
|
|
30
31
|
});
|
|
31
32
|
const active = await loadAuthoringActiveAuthority(repository, workdir, diagnostics);
|
|
33
|
+
if (validation.workspace)
|
|
34
|
+
try {
|
|
35
|
+
const changedPaths = active?.workdir === workdir
|
|
36
|
+
? changedWorkspacePaths(active.initial_task_base.workspace_manifest, validation.workspace)
|
|
37
|
+
: await changedWorkspacePathsFromHead(repository, workdir);
|
|
38
|
+
const contractFiles = Object.fromEntries(Object.entries(parsed.contract_files).map(([relative, hash]) => [
|
|
39
|
+
repoRelative(repository, path.join(workdir, ...relative.split("/"))),
|
|
40
|
+
hash,
|
|
41
|
+
]));
|
|
42
|
+
const checks = [
|
|
43
|
+
...validation.global_checks,
|
|
44
|
+
...validation.outcomes.flatMap((outcome) => outcome.acceptance.checks),
|
|
45
|
+
];
|
|
46
|
+
const declaredVerificationInputs = [
|
|
47
|
+
...contract.global.acceptance.checks,
|
|
48
|
+
...contract.outcomes.flatMap((outcome) => outcome.acceptance.checks),
|
|
49
|
+
].flatMap((check) => check.verification_inputs);
|
|
50
|
+
const firstLockManagedPaths = active?.workdir === workdir
|
|
51
|
+
? []
|
|
52
|
+
: await firstLockManagedWorkspacePaths(repository, changedPaths);
|
|
53
|
+
const classification = classifyWorkspaceScope(contract, changedPaths, protectedWorkspacePaths({
|
|
54
|
+
contract_files: contractFiles,
|
|
55
|
+
source_hashes: validation.source_hashes,
|
|
56
|
+
context_hashes: validation.context_snapshot?.sha256,
|
|
57
|
+
checks,
|
|
58
|
+
additional_files: [
|
|
59
|
+
...contract.task.source_paths,
|
|
60
|
+
...declaredVerificationInputs,
|
|
61
|
+
...firstLockManagedPaths,
|
|
62
|
+
],
|
|
63
|
+
}));
|
|
64
|
+
for (const error of workspaceScopeErrors(classification))
|
|
65
|
+
addDiagnosticError(diagnostics, new Error(error));
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
addDiagnosticError(diagnostics, error);
|
|
69
|
+
}
|
|
32
70
|
const normalizedDiagnostics = normalizeAuthoringDiagnostics(diagnostics);
|
|
33
71
|
const ready = !normalizedDiagnostics.some((item) => item.level === "error" || item.level === "decision_required");
|
|
34
72
|
return {
|
|
@@ -168,6 +168,20 @@ function flattenProductSemantics(projection) {
|
|
|
168
168
|
"accessibility",
|
|
169
169
|
])
|
|
170
170
|
fields.set(`${prefix}.controls.${control.key}.${field}`, control[field]);
|
|
171
|
+
for (const binding of outcome.surface_bindings ?? []) {
|
|
172
|
+
const bindingPrefix = `${prefix}.surface_bindings.${binding.key}`;
|
|
173
|
+
fields.set(`${bindingPrefix}.surface_ref`, binding.surface_ref);
|
|
174
|
+
fields.set(`${bindingPrefix}.target_ref`, binding.target_ref);
|
|
175
|
+
fields.set(`${bindingPrefix}.control_refs`, binding.control_refs);
|
|
176
|
+
fields.set(`${bindingPrefix}.route_binding_ref`, binding.route_binding_ref);
|
|
177
|
+
fields.set(`${bindingPrefix}.component_binding_refs`, binding.component_binding_refs);
|
|
178
|
+
fields.set(`${bindingPrefix}.root_journey_check_ref`, binding.root_journey_check_ref);
|
|
179
|
+
fields.set(`${bindingPrefix}.entry_action_ref`, binding.entry_action_ref);
|
|
180
|
+
for (const target of binding.design_targets)
|
|
181
|
+
fields.set(`${bindingPrefix}.design_targets.${target.key}`, target);
|
|
182
|
+
for (const blocker of binding.acceptance_blockers)
|
|
183
|
+
fields.set(`${bindingPrefix}.acceptance_blockers.${blocker.key}`, blocker);
|
|
184
|
+
}
|
|
171
185
|
for (const item of outcome.non_completing_outcomes)
|
|
172
186
|
fields.set(`${prefix}.non_completing.${item.key}`, item.statement);
|
|
173
187
|
}
|
|
@@ -77,6 +77,27 @@ export function projectProductSemantics(contract) {
|
|
|
77
77
|
feedback: control.feedback,
|
|
78
78
|
accessibility: control.accessibility,
|
|
79
79
|
})),
|
|
80
|
+
surface_bindings: [...(outcome.product.surface_bindings ?? [])]
|
|
81
|
+
.sort(keyOrder)
|
|
82
|
+
.map((binding) => ({
|
|
83
|
+
...binding,
|
|
84
|
+
control_refs: [...binding.control_refs].sort(),
|
|
85
|
+
component_binding_refs: [...binding.component_binding_refs].sort(),
|
|
86
|
+
design_targets: [...binding.design_targets]
|
|
87
|
+
.sort(keyOrder)
|
|
88
|
+
.map((target) => ({
|
|
89
|
+
...target,
|
|
90
|
+
source_paths: [...target.source_paths].sort(),
|
|
91
|
+
condition_keys: [...target.condition_keys].sort(),
|
|
92
|
+
claim_refs: [...target.claim_refs].sort(),
|
|
93
|
+
})),
|
|
94
|
+
acceptance_blockers: [...binding.acceptance_blockers]
|
|
95
|
+
.sort(keyOrder)
|
|
96
|
+
.map((blocker) => ({
|
|
97
|
+
...blocker,
|
|
98
|
+
refs: [...blocker.refs].sort(),
|
|
99
|
+
})),
|
|
100
|
+
})),
|
|
80
101
|
non_completing_outcomes: keyedStatements(outcome.product.non_completing_outcomes),
|
|
81
102
|
})),
|
|
82
103
|
};
|
|
@@ -65,6 +65,7 @@ export declare const AUTHORITY_FIELD_POLICY_REGISTRIES: {
|
|
|
65
65
|
requirements: "semantic_user_review";
|
|
66
66
|
owner_surfaces: "semantic_user_review";
|
|
67
67
|
controls: "semantic_user_review";
|
|
68
|
+
surface_bindings: "semantic_user_review";
|
|
68
69
|
non_completing_outcomes: "semantic_user_review";
|
|
69
70
|
};
|
|
70
71
|
readonly requirement: {
|
|
@@ -102,6 +103,38 @@ export declare const AUTHORITY_FIELD_POLICY_REGISTRIES: {
|
|
|
102
103
|
feedback: "semantic_user_review";
|
|
103
104
|
accessibility: "semantic_user_review";
|
|
104
105
|
};
|
|
106
|
+
readonly surface_binding: {
|
|
107
|
+
key: "identity";
|
|
108
|
+
surface_ref: "semantic_user_review";
|
|
109
|
+
target_ref: "semantic_user_review";
|
|
110
|
+
control_refs: "semantic_user_review";
|
|
111
|
+
route_binding_ref: "semantic_user_review";
|
|
112
|
+
component_binding_refs: "semantic_user_review";
|
|
113
|
+
root_journey_check_ref: "proof_additive";
|
|
114
|
+
entry_action_ref: "proof_additive";
|
|
115
|
+
design_targets: "semantic_user_review";
|
|
116
|
+
acceptance_blockers: "semantic_user_review";
|
|
117
|
+
};
|
|
118
|
+
readonly design_target: {
|
|
119
|
+
key: "identity";
|
|
120
|
+
interpretation: "semantic_user_review";
|
|
121
|
+
source_paths: "scope";
|
|
122
|
+
condition_keys: "semantic_user_review";
|
|
123
|
+
claim_refs: "proof_additive";
|
|
124
|
+
conformance_check_ref: "proof_additive";
|
|
125
|
+
conformance_assertion_ref: "proof_additive";
|
|
126
|
+
verification_method_bindings: "proof_additive";
|
|
127
|
+
actual_artifact_path: "output_requirement";
|
|
128
|
+
comparison_artifact_path: "output_requirement";
|
|
129
|
+
};
|
|
130
|
+
readonly design_blocker: {
|
|
131
|
+
key: "identity";
|
|
132
|
+
status: "semantic_user_review";
|
|
133
|
+
refs: "semantic_user_review";
|
|
134
|
+
source_item_refs: "semantic_user_review";
|
|
135
|
+
verification_methods: "proof_additive";
|
|
136
|
+
rationale: "semantic_user_review";
|
|
137
|
+
};
|
|
105
138
|
readonly outcome_technical: {
|
|
106
139
|
obligations: "semantic_user_review";
|
|
107
140
|
expected_change_paths: "scope";
|
|
@@ -48,6 +48,7 @@ const OUTCOME_PRODUCT_AUTHORITY_POLICY = {
|
|
|
48
48
|
requirements: "semantic_user_review",
|
|
49
49
|
owner_surfaces: "semantic_user_review",
|
|
50
50
|
controls: "semantic_user_review",
|
|
51
|
+
surface_bindings: "semantic_user_review",
|
|
51
52
|
non_completing_outcomes: "semantic_user_review",
|
|
52
53
|
};
|
|
53
54
|
const REQUIREMENT_AUTHORITY_POLICY = {
|
|
@@ -85,6 +86,38 @@ const CONTROL_AUTHORITY_POLICY = {
|
|
|
85
86
|
feedback: "semantic_user_review",
|
|
86
87
|
accessibility: "semantic_user_review",
|
|
87
88
|
};
|
|
89
|
+
const SURFACE_BINDING_AUTHORITY_POLICY = {
|
|
90
|
+
key: "identity",
|
|
91
|
+
surface_ref: "semantic_user_review",
|
|
92
|
+
target_ref: "semantic_user_review",
|
|
93
|
+
control_refs: "semantic_user_review",
|
|
94
|
+
route_binding_ref: "semantic_user_review",
|
|
95
|
+
component_binding_refs: "semantic_user_review",
|
|
96
|
+
root_journey_check_ref: "proof_additive",
|
|
97
|
+
entry_action_ref: "proof_additive",
|
|
98
|
+
design_targets: "semantic_user_review",
|
|
99
|
+
acceptance_blockers: "semantic_user_review",
|
|
100
|
+
};
|
|
101
|
+
const DESIGN_TARGET_AUTHORITY_POLICY = {
|
|
102
|
+
key: "identity",
|
|
103
|
+
interpretation: "semantic_user_review",
|
|
104
|
+
source_paths: "scope",
|
|
105
|
+
condition_keys: "semantic_user_review",
|
|
106
|
+
claim_refs: "proof_additive",
|
|
107
|
+
conformance_check_ref: "proof_additive",
|
|
108
|
+
conformance_assertion_ref: "proof_additive",
|
|
109
|
+
verification_method_bindings: "proof_additive",
|
|
110
|
+
actual_artifact_path: "output_requirement",
|
|
111
|
+
comparison_artifact_path: "output_requirement",
|
|
112
|
+
};
|
|
113
|
+
const DESIGN_BLOCKER_AUTHORITY_POLICY = {
|
|
114
|
+
key: "identity",
|
|
115
|
+
status: "semantic_user_review",
|
|
116
|
+
refs: "semantic_user_review",
|
|
117
|
+
source_item_refs: "semantic_user_review",
|
|
118
|
+
verification_methods: "proof_additive",
|
|
119
|
+
rationale: "semantic_user_review",
|
|
120
|
+
};
|
|
88
121
|
const OUTCOME_TECHNICAL_AUTHORITY_POLICY = {
|
|
89
122
|
obligations: "semantic_user_review",
|
|
90
123
|
expected_change_paths: "scope",
|
|
@@ -185,6 +218,9 @@ export const AUTHORITY_FIELD_POLICY_REGISTRIES = {
|
|
|
185
218
|
requirement: REQUIREMENT_AUTHORITY_POLICY,
|
|
186
219
|
owner: OWNER_AUTHORITY_POLICY,
|
|
187
220
|
control: CONTROL_AUTHORITY_POLICY,
|
|
221
|
+
surface_binding: SURFACE_BINDING_AUTHORITY_POLICY,
|
|
222
|
+
design_target: DESIGN_TARGET_AUTHORITY_POLICY,
|
|
223
|
+
design_blocker: DESIGN_BLOCKER_AUTHORITY_POLICY,
|
|
188
224
|
outcome_technical: OUTCOME_TECHNICAL_AUTHORITY_POLICY,
|
|
189
225
|
obligation: OBLIGATION_AUTHORITY_POLICY,
|
|
190
226
|
binding: BINDING_AUTHORITY_POLICY,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CompiledCheckV2, CompiledDeliveryContractV2, DeliveryContractV2 } from "./long-task-delivery-types.js";
|
|
2
2
|
export interface CheckRevisionAnalysis {
|
|
3
3
|
negative_assertions_removed: string[];
|
|
4
|
+
acceptance_semantics_reduced: string[];
|
|
4
5
|
proof_surfaces_changed: string[];
|
|
5
6
|
runner_definitions_changed: string[];
|
|
6
7
|
verification_inputs_added: string[];
|
|
@@ -2,6 +2,7 @@ import { addedInputPaths, addedVerificationInputs, bindingReductions, changedRun
|
|
|
2
2
|
export function analyzeCheckRevisions(beforeChecks, afterChecks) {
|
|
3
3
|
const result = {
|
|
4
4
|
negative_assertions_removed: [],
|
|
5
|
+
acceptance_semantics_reduced: [],
|
|
5
6
|
proof_surfaces_changed: [],
|
|
6
7
|
runner_definitions_changed: [],
|
|
7
8
|
verification_inputs_added: [],
|
|
@@ -19,6 +20,12 @@ export function analyzeCheckRevisions(beforeChecks, afterChecks) {
|
|
|
19
20
|
for (const assertion of before.negative_assertions)
|
|
20
21
|
if (!after.negative_assertions.some((item) => same(item, assertion)))
|
|
21
22
|
result.negative_assertions_removed.push(`${identity}:${assertion.key}`);
|
|
23
|
+
if (!same(before.execution_target, after.execution_target))
|
|
24
|
+
result.acceptance_semantics_reduced.push(`${identity}:execution_target`);
|
|
25
|
+
collectRemovedValues(result.acceptance_semantics_reduced, `${identity}:journey_role`, before.journey_roles, after.journey_roles);
|
|
26
|
+
collectRemovedValues(result.acceptance_semantics_reduced, `${identity}:scenario.given`, before.scenario.given, after.scenario.given);
|
|
27
|
+
collectRemovedValues(result.acceptance_semantics_reduced, `${identity}:scenario.when`, before.scenario.when, after.scenario.when);
|
|
28
|
+
collectAssertionReductions(result.acceptance_semantics_reduced, identity, before.positive_assertions, after.positive_assertions);
|
|
22
29
|
if (before.proof_surface !== after.proof_surface)
|
|
23
30
|
result.proof_surfaces_changed.push(`${identity}:${before.proof_surface}->${after.proof_surface}`);
|
|
24
31
|
result.runner_definitions_changed.push(...changedRunnerFields(identity, before, after));
|
|
@@ -32,6 +39,29 @@ export function analyzeCheckRevisions(beforeChecks, afterChecks) {
|
|
|
32
39
|
}
|
|
33
40
|
return result;
|
|
34
41
|
}
|
|
42
|
+
function collectRemovedValues(result, prefix, before, after) {
|
|
43
|
+
for (const value of before)
|
|
44
|
+
if (!after.some((candidate) => same(candidate, value)))
|
|
45
|
+
result.push(`${prefix}:${String(value)}`);
|
|
46
|
+
}
|
|
47
|
+
function collectAssertionReductions(result, identity, before, after) {
|
|
48
|
+
const next = new Map(after.map((assertion) => [assertion.key, assertion]));
|
|
49
|
+
for (const assertion of before) {
|
|
50
|
+
const candidate = next.get(assertion.key);
|
|
51
|
+
if (!candidate) {
|
|
52
|
+
result.push(`${identity}:positive_assertion.${assertion.key}:removed`);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const semanticChanged = assertion.criterion !== candidate.criterion ||
|
|
56
|
+
!same(assertion.claims, candidate.claims) ||
|
|
57
|
+
assertion.observation !== candidate.observation ||
|
|
58
|
+
assertion.operator !== candidate.operator ||
|
|
59
|
+
!same(assertion.expected, candidate.expected);
|
|
60
|
+
const capabilityRemoved = assertion.evidence_capabilities.some((capability) => !candidate.evidence_capabilities.includes(capability));
|
|
61
|
+
if (semanticChanged || capabilityRemoved)
|
|
62
|
+
result.push(`${identity}:positive_assertion.${assertion.key}:changed`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
35
65
|
export function analyzeOutcomeRevisions(previous, next) {
|
|
36
66
|
const result = {
|
|
37
67
|
owner_paths_expanded: [],
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AuthorityRevisionApprovalSummaryV2, AuthorityRevisionChangeClassV2, AuthorityRevisionDecisionBriefV2, AuthorityRevisionDecisionV2 } from "./long-task-authority-revision-types.js";
|
|
2
|
+
export declare function authorityRevisionDecisionNextAction(decision: AuthorityRevisionDecisionV2): string;
|
|
3
|
+
export declare function buildAuthorityRevisionDecisionBrief(summary: AuthorityRevisionApprovalSummaryV2, changeClass: AuthorityRevisionChangeClassV2, approvalRequired: boolean): AuthorityRevisionDecisionBriefV2;
|