project-tiny-context-harness 0.8.12 → 0.8.13

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 (158) hide show
  1. package/README.md +43 -19
  2. package/assets/README.md +81 -40
  3. package/assets/README.zh-CN.md +44 -22
  4. package/assets/agents/AGENTS_CORE.md +8 -4
  5. package/assets/skills/context_development_engineer/SKILL.md +9 -1
  6. package/assets/skills/design-resource-authoring/SKILL.md +7 -5
  7. package/assets/skills/design-resource-authoring/references/downstream-handoff.md +2 -2
  8. package/assets/skills/design-resource-authoring/references/open-design-provider.md +22 -2
  9. package/assets/skills/design-resource-authoring/references/recovery-and-writeback.md +199 -0
  10. package/assets/skills/design-resource-authoring/references/resource-selection.md +2 -2
  11. package/assets/skills/long-task-workflow/SKILL.md +6 -6
  12. package/assets/skills/long-task-workflow/references/contract-authoring.md +27 -22
  13. package/assets/skills/long-task-workflow/references/evidence-design.md +49 -32
  14. package/assets/skills/long-task-workflow/references/source-authoring.md +2 -2
  15. package/dist/commands/design-resource-recovery.d.ts +1 -0
  16. package/dist/commands/design-resource-recovery.js +152 -0
  17. package/dist/commands/design-resource.js +20 -1
  18. package/dist/commands/index.js +1 -1
  19. package/dist/lib/design-resource-reconciliation-codec.d.ts +2 -0
  20. package/dist/lib/design-resource-reconciliation-codec.js +174 -0
  21. package/dist/lib/design-resource-reconciliation-types.d.ts +62 -0
  22. package/dist/lib/design-resource-reconciliation-types.js +1 -0
  23. package/dist/lib/design-resource-reconciliation.d.ts +3 -0
  24. package/dist/lib/design-resource-reconciliation.js +224 -0
  25. package/dist/lib/design-resource-recovery-authority-policy.d.ts +8 -0
  26. package/dist/lib/design-resource-recovery-authority-policy.js +123 -0
  27. package/dist/lib/design-resource-recovery-catalog-resources.d.ts +6 -0
  28. package/dist/lib/design-resource-recovery-catalog-resources.js +121 -0
  29. package/dist/lib/design-resource-recovery-catalog-shape.d.ts +3 -0
  30. package/dist/lib/design-resource-recovery-catalog-shape.js +104 -0
  31. package/dist/lib/design-resource-recovery-catalog.d.ts +9 -0
  32. package/dist/lib/design-resource-recovery-catalog.js +103 -0
  33. package/dist/lib/design-resource-recovery-cleanup.d.ts +2 -0
  34. package/dist/lib/design-resource-recovery-cleanup.js +11 -0
  35. package/dist/lib/design-resource-recovery-codec-primitives.d.ts +19 -0
  36. package/dist/lib/design-resource-recovery-codec-primitives.js +92 -0
  37. package/dist/lib/design-resource-recovery-codec.d.ts +4 -0
  38. package/dist/lib/design-resource-recovery-codec.js +93 -0
  39. package/dist/lib/design-resource-recovery-current.d.ts +9 -0
  40. package/dist/lib/design-resource-recovery-current.js +41 -0
  41. package/dist/lib/design-resource-recovery-delta-policy.d.ts +5 -0
  42. package/dist/lib/design-resource-recovery-delta-policy.js +108 -0
  43. package/dist/lib/design-resource-recovery-files.d.ts +37 -0
  44. package/dist/lib/design-resource-recovery-files.js +204 -0
  45. package/dist/lib/design-resource-recovery-final-disposition-shape.d.ts +2 -0
  46. package/dist/lib/design-resource-recovery-final-disposition-shape.js +47 -0
  47. package/dist/lib/design-resource-recovery-patch-types.d.ts +54 -0
  48. package/dist/lib/design-resource-recovery-patch-types.js +1 -0
  49. package/dist/lib/design-resource-recovery-replay.d.ts +7 -0
  50. package/dist/lib/design-resource-recovery-replay.js +112 -0
  51. package/dist/lib/design-resource-recovery-repository-bindings.d.ts +9 -0
  52. package/dist/lib/design-resource-recovery-repository-bindings.js +49 -0
  53. package/dist/lib/design-resource-recovery-schema.d.ts +5 -0
  54. package/dist/lib/design-resource-recovery-schema.js +5 -0
  55. package/dist/lib/design-resource-recovery-shape.d.ts +10 -0
  56. package/dist/lib/design-resource-recovery-shape.js +184 -0
  57. package/dist/lib/design-resource-recovery-source-authority.d.ts +5 -0
  58. package/dist/lib/design-resource-recovery-source-authority.js +219 -0
  59. package/dist/lib/design-resource-recovery-text.d.ts +17 -0
  60. package/dist/lib/design-resource-recovery-text.js +186 -0
  61. package/dist/lib/design-resource-recovery-types.d.ts +197 -0
  62. package/dist/lib/design-resource-recovery-types.js +1 -0
  63. package/dist/lib/design-resource-recovery-writeback-policy.d.ts +5 -0
  64. package/dist/lib/design-resource-recovery-writeback-policy.js +326 -0
  65. package/dist/lib/design-resource-recovery-writeback-shape.d.ts +6 -0
  66. package/dist/lib/design-resource-recovery-writeback-shape.js +155 -0
  67. package/dist/lib/design-resource-recovery.d.ts +44 -0
  68. package/dist/lib/design-resource-recovery.js +216 -0
  69. package/dist/lib/long-task-acceptance-shape.js +8 -2
  70. package/dist/lib/long-task-activation-validation.js +13 -3
  71. package/dist/lib/long-task-admitted-observation-records.d.ts +25 -0
  72. package/dist/lib/long-task-admitted-observation-records.js +40 -0
  73. package/dist/lib/long-task-admitted-observation.d.ts +93 -0
  74. package/dist/lib/long-task-admitted-observation.js +201 -0
  75. package/dist/lib/long-task-artifacts.d.ts +1 -0
  76. package/dist/lib/long-task-artifacts.js +1 -0
  77. package/dist/lib/long-task-authority-material-diff.js +1 -0
  78. package/dist/lib/long-task-authority-policy.d.ts +2 -0
  79. package/dist/lib/long-task-authority-policy.js +2 -0
  80. package/dist/lib/long-task-authority-revision-details.js +3 -1
  81. package/dist/lib/long-task-authority.js +2 -1
  82. package/dist/lib/long-task-check-execution-policy.js +5 -0
  83. package/dist/lib/long-task-check-runner.d.ts +2 -2
  84. package/dist/lib/long-task-check-runner.js +440 -23
  85. package/dist/lib/long-task-claims.d.ts +18 -0
  86. package/dist/lib/long-task-claims.js +35 -0
  87. package/dist/lib/long-task-compact-structure-targets.js +1 -0
  88. package/dist/lib/long-task-conformance-policy.js +3 -1
  89. package/dist/lib/long-task-counterfactual-claim-policy.d.ts +3 -4
  90. package/dist/lib/long-task-counterfactual-claim-policy.js +11 -3
  91. package/dist/lib/long-task-counterfactual-sandbox.js +1 -0
  92. package/dist/lib/long-task-counterfactual-types.d.ts +2 -0
  93. package/dist/lib/long-task-delivery-compiler.js +2 -0
  94. package/dist/lib/long-task-evidence-capability-policy.d.ts +3 -2
  95. package/dist/lib/long-task-evidence-capability-policy.js +114 -8
  96. package/dist/lib/long-task-evidence-capability-runtime.d.ts +5 -2
  97. package/dist/lib/long-task-evidence-capability-runtime.js +149 -5
  98. package/dist/lib/long-task-evidence-sensitivity-policy.d.ts +9 -0
  99. package/dist/lib/long-task-evidence-sensitivity-policy.js +31 -1
  100. package/dist/lib/long-task-evidence-v2.d.ts +4 -4
  101. package/dist/lib/long-task-evidence-v2.js +321 -43
  102. package/dist/lib/long-task-exact-comparison.d.ts +16 -0
  103. package/dist/lib/long-task-exact-comparison.js +28 -0
  104. package/dist/lib/long-task-execution-observation.d.ts +24 -0
  105. package/dist/lib/long-task-execution-observation.js +332 -0
  106. package/dist/lib/long-task-explain-acceptance-link.d.ts +4 -0
  107. package/dist/lib/long-task-explain-acceptance-link.js +4 -0
  108. package/dist/lib/long-task-explain-claim-links.d.ts +2 -0
  109. package/dist/lib/long-task-explain-claim-links.js +2 -0
  110. package/dist/lib/long-task-explain-source-links.d.ts +6 -0
  111. package/dist/lib/long-task-final-v2.js +7 -4
  112. package/dist/lib/long-task-json-pointer-observation.d.ts +59 -0
  113. package/dist/lib/long-task-json-pointer-observation.js +184 -0
  114. package/dist/lib/long-task-observation-artifact.d.ts +8 -0
  115. package/dist/lib/long-task-observation-artifact.js +58 -0
  116. package/dist/lib/long-task-observation-authority.d.ts +17 -0
  117. package/dist/lib/long-task-observation-authority.js +348 -0
  118. package/dist/lib/long-task-paths.js +1 -1
  119. package/dist/lib/long-task-process-observation.d.ts +6 -0
  120. package/dist/lib/long-task-process-observation.js +117 -0
  121. package/dist/lib/long-task-process-runtime-closure.d.ts +13 -0
  122. package/dist/lib/long-task-process-runtime-closure.js +175 -0
  123. package/dist/lib/long-task-progress.js +2 -0
  124. package/dist/lib/long-task-protected-files.d.ts +1 -1
  125. package/dist/lib/long-task-protected-files.js +1 -30
  126. package/dist/lib/long-task-risk.js +8 -3
  127. package/dist/lib/long-task-root-shape.js +10 -1
  128. package/dist/lib/long-task-runner-environment.d.ts +1 -1
  129. package/dist/lib/long-task-runner-environment.js +4 -4
  130. package/dist/lib/long-task-runner-freeze.d.ts +4 -2
  131. package/dist/lib/long-task-runner-freeze.js +128 -28
  132. package/dist/lib/long-task-runtime-types.d.ts +111 -0
  133. package/dist/lib/long-task-scoped-binding.d.ts +13 -0
  134. package/dist/lib/long-task-scoped-binding.js +11 -0
  135. package/dist/lib/long-task-semantic-contract-types.d.ts +1 -0
  136. package/dist/lib/long-task-semantic-fact-contract-closure.js +3 -3
  137. package/dist/lib/long-task-semantic-fact-evidence.d.ts +3 -3
  138. package/dist/lib/long-task-semantic-fact-evidence.js +75 -58
  139. package/dist/lib/long-task-source-claim-validation.js +4 -1
  140. package/dist/lib/long-task-source-target-continuity.d.ts +2 -2
  141. package/dist/lib/long-task-source-target-continuity.js +35 -2
  142. package/dist/lib/long-task-source-target-index.d.ts +3 -0
  143. package/dist/lib/long-task-source-target-index.js +19 -0
  144. package/dist/lib/long-task-stage-policy.js +10 -4
  145. package/dist/lib/long-task-static-observation-freeze.d.ts +83 -0
  146. package/dist/lib/long-task-static-observation-freeze.js +428 -0
  147. package/dist/lib/long-task-status-projection.js +5 -1
  148. package/dist/lib/long-task-target-policy.d.ts +1 -1
  149. package/dist/lib/long-task-target-policy.js +3 -0
  150. package/dist/lib/long-task-verifier-dependency-closure.js +7 -3
  151. package/dist/lib/long-task-verifier-v2.js +70 -9
  152. package/dist/lib/long-task-workspace.d.ts +1 -1
  153. package/dist/lib/long-task-workspace.js +1 -12
  154. package/dist/lib/repository-path-safety.d.ts +14 -0
  155. package/dist/lib/repository-path-safety.js +126 -0
  156. package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +53 -8
  157. package/migrations/README.md +77 -0
  158. package/package.json +1 -1
@@ -0,0 +1,117 @@
1
+ import { assertJsonTree, decodeUtf8Json, JSON_POINTER_EXACT_CAPABILITY, JSON_POINTER_EXACT_LIMITS, observationErrorMessage, parseJsonWithoutDuplicateKeys, resolveJsonPointer, validateJsonPointerExactLocator, } from "./long-task-json-pointer-observation.js";
2
+ import { canonicalValueJson, sha256Hex } from "./strict-codec.js";
3
+ export const PRODUCT_OBSERVATION_SCHEMA_VERSION = "ty-context-product-observation-v1";
4
+ export function decodeProductObservationEnvelope(input) {
5
+ let artifactSha256;
6
+ let parsed;
7
+ try {
8
+ if (input.bytes.byteLength > JSON_POINTER_EXACT_LIMITS.max_file_bytes)
9
+ throw new Error("observation_artifact_size_limit");
10
+ const strict = parseJsonWithoutDuplicateKeys(decodeUtf8Json(input.bytes));
11
+ assertJsonTree(strict, 0);
12
+ parsed = record(strict);
13
+ artifactSha256 = sha256Hex(input.bytes);
14
+ }
15
+ catch (error) {
16
+ throw invalid(`process_observation_decode_invalid:${observationErrorMessage(error)}`);
17
+ }
18
+ requireExactKeys(parsed, ["observations", "schema_version"]);
19
+ if (parsed.schema_version !== PRODUCT_OBSERVATION_SCHEMA_VERSION)
20
+ throw invalid("process_observation_schema_invalid");
21
+ const observations = record(parsed.observations);
22
+ const expectedIdentities = expectedObservationIdentities(input.authorities);
23
+ const actualIdentities = Object.keys(observations).sort();
24
+ if (!sameStrings(actualIdentities, expectedIdentities))
25
+ throw invalid(`process_observation_identity_set_mismatch:expected=${expectedIdentities.join(",")}:actual=${actualIdentities.join(",")}`);
26
+ if (expectedIdentities.length >
27
+ JSON_POINTER_EXACT_LIMITS.max_artifacts_per_check)
28
+ throw invalid("process_observation_identity_count_limit");
29
+ const valueSha256 = {};
30
+ const packageObservations = [];
31
+ for (const observationIdentity of expectedIdentities) {
32
+ const pointer = observationPointer(observationIdentity);
33
+ try {
34
+ validateJsonPointerExactLocator({ kind: "json_pointer", value: pointer });
35
+ }
36
+ catch (error) {
37
+ throw invalid(`process_observation_decode_invalid:${observationErrorMessage(error)}`);
38
+ }
39
+ for (const authority of input.authorities)
40
+ if (authority.observation_identity === observationIdentity &&
41
+ (authority.authority !== "package_process_json_exact" ||
42
+ authority.locator_policy.kind !== "fixed_json_pointer" ||
43
+ authority.locator_policy.value !== pointer))
44
+ throw invalid("process_observation_authority_invalid");
45
+ let rawValue;
46
+ try {
47
+ rawValue = resolveJsonPointer(parsed, pointer);
48
+ }
49
+ catch (error) {
50
+ throw invalid(`process_observation_decode_invalid:${observationErrorMessage(error)}`);
51
+ }
52
+ const canonical = canonicalValueJson(rawValue);
53
+ if (Buffer.byteLength(canonical, "utf8") >
54
+ JSON_POINTER_EXACT_LIMITS.max_canonical_value_bytes)
55
+ throw invalid("process_observation_value_size_limit");
56
+ valueSha256[observationIdentity] = sha256Hex(canonical);
57
+ for (const authority of input.authorities.filter((candidate) => candidate.observation_identity === observationIdentity))
58
+ packageObservations.push({
59
+ authority: "package_process_json_exact",
60
+ observation_identity: observationIdentity,
61
+ assertion_ref: authority.assertion_ref,
62
+ obligation_ref: authority.obligation_ref,
63
+ method: authority.method,
64
+ raw_value: rawValue,
65
+ observation: {
66
+ capability: JSON_POINTER_EXACT_CAPABILITY,
67
+ artifact_path: "process.stdout.json",
68
+ artifact_sha256: artifactSha256,
69
+ locator: { kind: "json_pointer", value: pointer },
70
+ value_sha256: valueSha256[observationIdentity],
71
+ canonical_value_bytes: Buffer.byteLength(canonical, "utf8"),
72
+ sensitivity: "plain",
73
+ },
74
+ reason: null,
75
+ });
76
+ }
77
+ return {
78
+ schema_version: PRODUCT_OBSERVATION_SCHEMA_VERSION,
79
+ artifact_sha256: artifactSha256,
80
+ observations,
81
+ value_sha256_by_identity: valueSha256,
82
+ package_observations: packageObservations,
83
+ };
84
+ }
85
+ function expectedObservationIdentities(authorities) {
86
+ if (!authorities.length)
87
+ throw invalid("process_observation_authority_required");
88
+ const identities = new Set();
89
+ for (const authority of authorities) {
90
+ if (authority.authority !== "package_process_json_exact")
91
+ throw invalid("process_observation_authority_invalid");
92
+ if (!authority.observation_identity)
93
+ throw invalid("process_observation_identity_invalid");
94
+ identities.add(authority.observation_identity);
95
+ }
96
+ return [...identities].sort();
97
+ }
98
+ function record(value) {
99
+ if (!value || typeof value !== "object" || Array.isArray(value))
100
+ throw invalid("process_observation_object_required");
101
+ return value;
102
+ }
103
+ function requireExactKeys(value, expected) {
104
+ const actual = Object.keys(value).sort();
105
+ if (!sameStrings(actual, [...expected].sort()))
106
+ throw invalid("process_observation_envelope_fields_invalid");
107
+ }
108
+ function observationPointer(identityValue) {
109
+ return `/observations/${identityValue.replace(/~/gu, "~0").replace(/\//gu, "~1")}`;
110
+ }
111
+ function sameStrings(left, right) {
112
+ return (left.length === right.length &&
113
+ left.every((value, index) => value === right[index]));
114
+ }
115
+ function invalid(code) {
116
+ return new Error(code);
117
+ }
@@ -0,0 +1,13 @@
1
+ import type { CompiledObservationAuthorityV2, CompiledProcessRuntimeClosureV2, DeliveryCheckV2, ExecutionTargetV2, FrozenRunnerV2, SourceBackedExecutionTargetV2 } from "./long-task-delivery-types.js";
2
+ import type { ScopedDeliveryBindingV2 } from "./long-task-scoped-binding.js";
3
+ export interface CompileProcessRuntimeClosureInput {
4
+ check: DeliveryCheckV2;
5
+ runner: FrozenRunnerV2;
6
+ execution_target: ExecutionTargetV2;
7
+ observation_authorities: readonly CompiledObservationAuthorityV2[];
8
+ production_bindings: readonly ScopedDeliveryBindingV2[];
9
+ production_owner_paths: readonly string[];
10
+ source_backed_execution_target: SourceBackedExecutionTargetV2 | null;
11
+ protected_authority_paths: readonly string[];
12
+ }
13
+ export declare function compileProcessRuntimeClosure(input: CompileProcessRuntimeClosureInput): CompiledProcessRuntimeClosureV2 | null;
@@ -0,0 +1,175 @@
1
+ import path from "node:path";
2
+ import { matchesRepoPattern, normalizeRepositoryFile, } from "./long-task-paths.js";
3
+ import { canonicalValueJson, sha256Hex } from "./strict-codec.js";
4
+ export function compileProcessRuntimeClosure(input) {
5
+ const processAuthorities = input.observation_authorities.filter((authority) => authority.authority === "package_process_json_exact");
6
+ if (!processAuthorities.length)
7
+ return null;
8
+ const targetRef = input.execution_target.key;
9
+ const sourceTarget = input.source_backed_execution_target;
10
+ if (!sourceTarget || sourceTarget.target_ref !== targetRef)
11
+ fail("process_root_source_binding_required", targetRef);
12
+ const rootTarget = normalizeRepositoryFile(input.execution_target.root_entrypoint, `${input.check.key}.process_root`);
13
+ const productionBindings = [...input.production_bindings];
14
+ requireProductionOwnership(input, rootTarget, targetRef);
15
+ const rootBindings = bindingsContaining(productionBindings, rootTarget);
16
+ if (!rootBindings.length)
17
+ fail("process_root_production_binding_required", `${targetRef}:${rootTarget}`);
18
+ const rootArgvFiles = argvAttributedRepositoryFiles(input.execution_target.root_argv ?? [], input.runner.resolved_cwd, productionBindings, targetRef);
19
+ const selectedBindings = new Map();
20
+ for (const binding of rootBindings)
21
+ selectBinding(selectedBindings, binding);
22
+ for (const argvFile of rootArgvFiles) {
23
+ requireProductionOwnership(input, argvFile, targetRef);
24
+ const bindings = bindingsContaining(productionBindings, argvFile);
25
+ if (!bindings.length)
26
+ fail("process_root_production_binding_required", `${targetRef}:${argvFile}`);
27
+ for (const binding of bindings)
28
+ selectBinding(selectedBindings, binding);
29
+ }
30
+ const productionCarrierFiles = new Set();
31
+ for (const carrierRef of processAuthorities.flatMap((authority) => authority.carrier_refs)) {
32
+ const matchingBindings = productionBindings.filter((scoped) => scoped.binding_ref === carrierRef.binding_ref &&
33
+ carrierRef.carrier_paths.every((carrierPath) => scoped.binding.carrier_paths.includes(carrierPath)));
34
+ if (!matchingBindings.length)
35
+ fail("process_root_production_binding_required", `${targetRef}:${carrierRef.binding_ref}`);
36
+ for (const binding of matchingBindings) {
37
+ selectBinding(selectedBindings, binding);
38
+ for (const carrierPath of carrierRef.carrier_paths) {
39
+ let carrierFile;
40
+ try {
41
+ carrierFile = normalizeRepositoryFile(carrierPath, `${input.check.key}.process_carrier`);
42
+ }
43
+ catch {
44
+ fail("process_runtime_carrier_exact_path_required", `${targetRef}:${carrierRef.binding_ref}:${carrierPath}`);
45
+ }
46
+ productionCarrierFiles.add(carrierFile);
47
+ }
48
+ }
49
+ }
50
+ const allowedRuntimeFiles = new Set([rootTarget, ...rootArgvFiles]);
51
+ for (const file of productionCarrierFiles)
52
+ allowedRuntimeFiles.add(file);
53
+ for (const file of allowedRuntimeFiles) {
54
+ requireProductionOwnership(input, file, targetRef);
55
+ validateConcreteRoleSeparation(input, file);
56
+ }
57
+ const projection = {
58
+ target_ref: targetRef,
59
+ source_target: sourceTarget,
60
+ root_target: rootTarget,
61
+ root_argv_files: [...new Set(rootArgvFiles)].sort(),
62
+ production_carrier_files: [...productionCarrierFiles].sort(),
63
+ allowed_runtime_files: [...allowedRuntimeFiles].sort(),
64
+ production_binding_refs: [...selectedBindings.keys()].sort(),
65
+ forbidden_role_matches: [],
66
+ };
67
+ return {
68
+ ...projection,
69
+ closure_identity: sha256Hex(canonicalValueJson(runtimeExecutionClosureProjection(projection))),
70
+ };
71
+ }
72
+ function runtimeExecutionClosureProjection(closure) {
73
+ return {
74
+ target_ref: closure.target_ref,
75
+ source_target: closure.source_target,
76
+ root_target: closure.root_target,
77
+ root_argv_files: closure.root_argv_files,
78
+ production_carrier_files: closure.production_carrier_files,
79
+ allowed_runtime_files: closure.allowed_runtime_files,
80
+ forbidden_role_matches: closure.forbidden_role_matches,
81
+ };
82
+ }
83
+ function validateConcreteRoleSeparation(input, file) {
84
+ const expected = firstMatchingPattern(file, input.protected_authority_paths);
85
+ if (expected)
86
+ fail("process_runtime_input_expected_authority_forbidden", `${input.check.key}:${file}:${expected}`);
87
+ const verification = firstMatchingPattern(file, input.check.verification_inputs);
88
+ if (verification)
89
+ fail("process_runtime_input_verification_role_forbidden", `${input.check.key}:${file}:${verification}`);
90
+ const evidence = firstMatchingPattern(file, [
91
+ ...input.check.expected_output_paths,
92
+ ...input.check.artifact_globs,
93
+ ]);
94
+ if (evidence)
95
+ fail("process_runtime_input_evidence_role_forbidden", `${input.check.key}:${file}:${evidence}`);
96
+ }
97
+ function requireProductionOwnership(input, file, targetRef) {
98
+ if (!input.production_owner_paths.some((pattern) => matchesRepoPattern(file, pattern)))
99
+ fail("process_root_production_binding_required", `${targetRef}:${file}:production_owner`);
100
+ }
101
+ function bindingsContaining(bindings, file) {
102
+ return bindings.filter((scoped) => scoped.binding.carrier_paths.some((pattern) => matchesRepoPattern(file, pattern)));
103
+ }
104
+ function selectBinding(selected, scoped) {
105
+ const existing = selected.get(scoped.binding_ref);
106
+ if (existing && canonicalValueJson(existing) !== canonicalValueJson(scoped))
107
+ fail("process_root_production_binding_required", `${scoped.binding_ref}:ambiguous`);
108
+ selected.set(scoped.binding_ref, scoped);
109
+ }
110
+ function argvAttributedRepositoryFiles(argv, cwd, bindings, targetRef) {
111
+ const result = new Set();
112
+ for (const argument of argv) {
113
+ const value = rootArgvPathValue(argument);
114
+ if (!value)
115
+ continue;
116
+ if (unsafeArgvPathValue(value))
117
+ fail("process_root_argv_unsafe", `${targetRef}:${argument}`);
118
+ const candidate = path.posix.join(cwd === "." ? "" : cwd, value);
119
+ let normalized;
120
+ try {
121
+ normalized = normalizeRepositoryFile(candidate, "process_root_argv");
122
+ }
123
+ catch {
124
+ fail("process_root_argv_unsafe", `${targetRef}:${argument}`);
125
+ }
126
+ if (bindingsContaining(bindings, normalized).length)
127
+ result.add(normalized);
128
+ }
129
+ return [...result].sort();
130
+ }
131
+ function rootArgvPathValue(argument) {
132
+ const parsedArgument = unwrapCompleteQuoteLayer(argument.replace(/\\/gu, "/"));
133
+ const portable = parsedArgument.value;
134
+ if (!portable)
135
+ return null;
136
+ // A compound shell command is not one finite argv file token. In
137
+ // particular, do not search inside it for a path-shaped substring.
138
+ if (!parsedArgument.quoted && /\s/u.test(portable))
139
+ return null;
140
+ // A single-letter slash switch is an argv label (for example cmd.exe /d),
141
+ // not a repository path. Longer slash-prefixed values remain absolute and
142
+ // fail closed below.
143
+ if (/^\/[A-Za-z?]$/u.test(portable))
144
+ return null;
145
+ if (!portable.startsWith("--"))
146
+ return portable;
147
+ const separator = portable.indexOf("=");
148
+ if (separator <= 2 || separator === portable.length - 1)
149
+ return null;
150
+ const parsedValue = unwrapCompleteQuoteLayer(portable.slice(separator + 1));
151
+ if (!parsedValue.value)
152
+ return null;
153
+ if (!parsedValue.quoted && /\s/u.test(parsedValue.value))
154
+ return null;
155
+ return parsedValue.value;
156
+ }
157
+ function unwrapCompleteQuoteLayer(value) {
158
+ const quote = value[0];
159
+ if ((quote === '"' || quote === "'") && value.at(-1) === quote)
160
+ return { value: value.slice(1, -1), quoted: true };
161
+ return { value, quoted: false };
162
+ }
163
+ function unsafeArgvPathValue(value) {
164
+ return (/["']/u.test(value) ||
165
+ value.startsWith("/") ||
166
+ /^[A-Za-z]:\//u.test(value) ||
167
+ /^file:/iu.test(value) ||
168
+ /^[A-Za-z][A-Za-z0-9+.-]*:\/\//u.test(value));
169
+ }
170
+ function firstMatchingPattern(file, patterns) {
171
+ return patterns.find((pattern) => matchesRepoPattern(file, pattern)) ?? null;
172
+ }
173
+ function fail(code, detail) {
174
+ throw new Error(`${code}:${detail}`);
175
+ }
@@ -81,6 +81,8 @@ export function checkIdentity(check) {
81
81
  execution_target_definition: check.execution_target_definition,
82
82
  scenario: check.scenario,
83
83
  environment_requirements: check.environment_requirements,
84
+ observation_authorities: check.observation_authorities,
85
+ process_runtime_closure: check.process_runtime_closure,
84
86
  }));
85
87
  }
86
88
  function runnerVerifierIdentity(compiled, check) {
@@ -1 +1 @@
1
- export declare function assertProtectedRepositoryFile(repositoryInput: string, fileInput: string, label: string): Promise<string>;
1
+ export { assertProtectedRepositoryFile } from "./repository-path-safety.js";
@@ -1,30 +1 @@
1
- import { lstat, realpath } from "node:fs/promises";
2
- import path from "node:path";
3
- export async function assertProtectedRepositoryFile(repositoryInput, fileInput, label) {
4
- const repositoryPath = path.resolve(repositoryInput);
5
- const repository = await realpath(repositoryPath);
6
- const candidate = path.resolve(fileInput);
7
- assertInside(repositoryPath, candidate, label, fileInput);
8
- const info = await lstat(candidate).catch(() => null);
9
- if (!info)
10
- throw new Error(`protected_input_not_found:${label}:${display(fileInput)}`);
11
- if (info.isSymbolicLink())
12
- throw new Error(`protected_input_symlink_not_allowed:${label}:${display(fileInput)}`);
13
- if (!info.isFile())
14
- throw new Error(`protected_input_not_regular_file:${label}:${display(fileInput)}`);
15
- const resolved = await realpath(candidate);
16
- assertInside(repository, resolved, label, fileInput);
17
- if (typeof info.nlink === "number" && info.nlink > 1)
18
- throw new Error(`protected_input_hardlink_not_allowed:${label}:${display(fileInput)}`);
19
- return resolved;
20
- }
21
- function assertInside(repository, candidate, label, original) {
22
- const relative = path.relative(repository, candidate);
23
- if (relative === ".." ||
24
- relative.startsWith(`..${path.sep}`) ||
25
- path.isAbsolute(relative))
26
- throw new Error(`protected_input_realpath_outside_repository:${label}:${display(original)}`);
27
- }
28
- function display(file) {
29
- return file.replace(/\\/gu, "/");
30
- }
1
+ export { assertProtectedRepositoryFile } from "./repository-path-safety.js";
@@ -1,3 +1,4 @@
1
+ import { outcomeResultExternallyBlocked } from "./long-task-claims.js";
1
2
  const STRICT_FACTS = new Set([
2
3
  "public_api_or_schema_change",
3
4
  "persistent_data_change",
@@ -45,15 +46,16 @@ export function validateRiskProof(contract, decision) {
45
46
  for (const check of contract.global.acceptance.checks)
46
47
  validateCheck(check, "global", errors);
47
48
  for (const outcome of contract.outcomes)
48
- validateOutcome(outcome, errors);
49
+ validateOutcome(contract, outcome, errors);
49
50
  if (decision.effective_level === "strict")
50
51
  validateStrict(contract, decision, errors);
51
52
  if (errors.length)
52
53
  throw new Error(`delivery_contract_preflight_failed:\n${errors.join("\n")}`);
53
54
  }
54
- function validateOutcome(outcome, errors) {
55
+ function validateOutcome(contract, outcome, errors) {
55
56
  const checks = new Map(outcome.acceptance.checks.map((check) => [check.key, check]));
56
- if (!checks.size)
57
+ const resultExternallyBlocked = outcomeResultExternallyBlocked(contract, outcome.key);
58
+ if (!checks.size && !resultExternallyBlocked)
57
59
  errors.push(`outcome_without_executable_check:${outcome.key}`);
58
60
  if (!outcome.technical.expected_change_paths.length)
59
61
  errors.push(`expected_change_paths_empty:${outcome.key}`);
@@ -61,6 +63,7 @@ function validateOutcome(outcome, errors) {
61
63
  validateCheck(check, outcome.key, errors);
62
64
  if ((outcome.product.owner_surfaces.length ||
63
65
  outcome.product.controls.length) &&
66
+ !resultExternallyBlocked &&
64
67
  ![...checks.values()].some((check) => check.proof_surface === "ui_browser"))
65
68
  errors.push(`ui_outcome_requires_ui_browser_proof:${outcome.key}`);
66
69
  const referenced = [
@@ -78,6 +81,8 @@ function validateOutcome(outcome, errors) {
78
81
  function validateStrict(contract, decision, errors) {
79
82
  const explicitStrictWithoutFacts = contract.risk.requested_level === "strict" && decision.reasons.length === 0;
80
83
  for (const outcome of contract.outcomes) {
84
+ if (outcomeResultExternallyBlocked(contract, outcome.key))
85
+ continue;
81
86
  const facts = new Set(decision.reasons_by_outcome[outcome.key]);
82
87
  const checks = outcome.acceptance.checks;
83
88
  const hasNegative = checks.some((check) => check.negative_assertions.length > 0);
@@ -53,7 +53,7 @@ export function parseTask(value) {
53
53
  "runtime_family",
54
54
  "root_entrypoint",
55
55
  "capabilities",
56
- ]);
56
+ ], ["root_argv"]);
57
57
  return {
58
58
  key: key(target.key, `${label}.key`),
59
59
  description: string(target.description, `${label}.description`),
@@ -67,6 +67,15 @@ export function parseTask(value) {
67
67
  "external",
68
68
  ], `${label}.runtime_family`),
69
69
  root_entrypoint: string(target.root_entrypoint, `${label}.root_entrypoint`),
70
+ ...(Object.hasOwn(target, "root_argv")
71
+ ? {
72
+ root_argv: strings(target.root_argv, `${label}.root_argv`).map((argument, argumentIndex) => {
73
+ if (argument.includes("\0"))
74
+ throw new Error(`delivery_contract_invalid:execution_target_root_argv_invalid:${label}:${argumentIndex}`);
75
+ return argument;
76
+ }),
77
+ }
78
+ : {}),
70
79
  capabilities: strings(target.capabilities, `${label}.capabilities`).map((item, capabilityIndex) => literal(item, EXECUTION_TARGET_CAPABILITIES, `${label}.capabilities[${capabilityIndex}]`)),
71
80
  };
72
81
  }),
@@ -1,5 +1,5 @@
1
1
  import type { EnvironmentRequirementV2 } from "./long-task-delivery-types.js";
2
- export declare function runnerEnvironment(requirements: EnvironmentRequirementV2[]): NodeJS.ProcessEnv;
2
+ export declare function runnerEnvironment(requirements: EnvironmentRequirementV2[], mode?: "legacy_check" | "product_observation"): NodeJS.ProcessEnv;
3
3
  export declare function declaredEnvironmentValues(requirements: EnvironmentRequirementV2[]): string[];
4
4
  export declare function outputContainsDeclaredEnvironmentValue(raw: {
5
5
  stdout: Buffer;
@@ -21,10 +21,10 @@ const BASE_ENVIRONMENT_KEYS = [
21
21
  "NO_COLOR",
22
22
  "FORCE_COLOR",
23
23
  ];
24
- export function runnerEnvironment(requirements) {
25
- const environment = {
26
- TY_CONTEXT_CHECK_PROTOCOL: "long-task-check-result-v3",
27
- };
24
+ export function runnerEnvironment(requirements, mode = "legacy_check") {
25
+ const environment = {};
26
+ if (mode === "legacy_check")
27
+ environment.TY_CONTEXT_CHECK_PROTOCOL = "long-task-check-result-v3";
28
28
  for (const key of BASE_ENVIRONMENT_KEYS)
29
29
  copyEnvironmentValue(environment, key);
30
30
  for (const requirement of requirements)
@@ -1,2 +1,4 @@
1
- import type { CompiledCheckV2, CompiledDesignTargetV2, DeliveryCheckV2, ExecutionTargetV2, SemanticFactExpectationV2, WorkspaceManifestV2 } from "./long-task-delivery-types.js";
2
- export declare function freezeDeliveryCheck(check: DeliveryCheckV2, outcomeKey: string | null, repository: string, baseline: WorkspaceManifestV2, executionTarget: ExecutionTargetV2, knownExecutionTargets: ExecutionTargetV2[], designConformanceTargets: CompiledDesignTargetV2[], semanticFactExpectations: SemanticFactExpectationV2[], protectedAuthorityPaths?: readonly string[]): Promise<CompiledCheckV2>;
1
+ import type { CompiledCheckV2, CompiledDesignTargetV2, DeliveryCheckV2, ExecutionTargetV2, SemanticFactExpectationV2, SourceBackedExecutionTargetV2, WorkspaceManifestV2 } from "./long-task-delivery-types.js";
2
+ import type { ScopedDeliveryBindingV2 } from "./long-task-scoped-binding.js";
3
+ export declare function freezeDeliveryCheck(check: DeliveryCheckV2, outcomeKey: string | null, repository: string, baseline: WorkspaceManifestV2, executionTarget: ExecutionTargetV2, knownExecutionTargets: ExecutionTargetV2[], designConformanceTargets: CompiledDesignTargetV2[], semanticFactExpectations: SemanticFactExpectationV2[], productionBindings: ScopedDeliveryBindingV2[], productionOwnerPaths: string[], sourceBackedExecutionTarget: SourceBackedExecutionTargetV2 | null, protectedAuthorityPaths?: readonly string[]): Promise<CompiledCheckV2>;
4
+ export declare function playwrightConfigArgument(argv: readonly string[]): string | null;