project-tiny-context-harness 0.7.3 → 0.7.5

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