@ttsc/unplugin 0.34.3 → 0.36.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.
Files changed (127) hide show
  1. package/lib/core/transform/cache/TtscCachedProjectTransform.d.cts +22 -0
  2. package/lib/core/transform/cache/TtscCachedProjectTransform.d.mts +22 -0
  3. package/lib/core/transform/cache/TtscCachedProjectTransform.d.ts +22 -0
  4. package/lib/core/transform/deliverCachedTransform.js +4 -1
  5. package/lib/core/transform/deliverCachedTransform.js.map +1 -1
  6. package/lib/core/transform/deliverCachedTransform.mjs +4 -1
  7. package/lib/core/transform/deliverCachedTransform.mjs.map +1 -1
  8. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.d.cts +16 -0
  9. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.d.mts +16 -0
  10. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.d.ts +16 -0
  11. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.js +28 -0
  12. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.js.map +1 -0
  13. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.mjs +26 -0
  14. package/lib/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.mjs.map +1 -0
  15. package/lib/core/transform/generation/TtscGenerationProofFailures.d.cts +19 -0
  16. package/lib/core/transform/generation/TtscGenerationProofFailures.d.mts +19 -0
  17. package/lib/core/transform/generation/TtscGenerationProofFailures.d.ts +19 -0
  18. package/lib/core/transform/generation/canDeliverCompilerSnapshot.d.cts +25 -0
  19. package/lib/core/transform/generation/canDeliverCompilerSnapshot.d.mts +25 -0
  20. package/lib/core/transform/generation/canDeliverCompilerSnapshot.d.ts +25 -0
  21. package/lib/core/transform/generation/canDeliverCompilerSnapshot.js +42 -0
  22. package/lib/core/transform/generation/canDeliverCompilerSnapshot.js.map +1 -0
  23. package/lib/core/transform/generation/canDeliverCompilerSnapshot.mjs +40 -0
  24. package/lib/core/transform/generation/canDeliverCompilerSnapshot.mjs.map +1 -0
  25. package/lib/core/transform/generation/captureTransformGeneration.js +35 -11
  26. package/lib/core/transform/generation/captureTransformGeneration.js.map +1 -1
  27. package/lib/core/transform/generation/captureTransformGeneration.mjs +35 -11
  28. package/lib/core/transform/generation/captureTransformGeneration.mjs.map +1 -1
  29. package/lib/core/transform/generation/captureTransformSourceHashes.d.cts +8 -6
  30. package/lib/core/transform/generation/captureTransformSourceHashes.d.mts +8 -6
  31. package/lib/core/transform/generation/captureTransformSourceHashes.d.ts +8 -6
  32. package/lib/core/transform/generation/captureTransformSourceHashes.js +16 -8
  33. package/lib/core/transform/generation/captureTransformSourceHashes.js.map +1 -1
  34. package/lib/core/transform/generation/captureTransformSourceHashes.mjs +16 -8
  35. package/lib/core/transform/generation/captureTransformSourceHashes.mjs.map +1 -1
  36. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.d.cts +18 -0
  37. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.d.mts +18 -0
  38. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.d.ts +18 -0
  39. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.js +75 -0
  40. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.js.map +1 -0
  41. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.mjs +73 -0
  42. package/lib/core/transform/generation/compilerSnapshotFailureClassifier.mjs.map +1 -0
  43. package/lib/core/transform/generation/createGenerationProofFailures.d.cts +3 -3
  44. package/lib/core/transform/generation/createGenerationProofFailures.d.mts +3 -3
  45. package/lib/core/transform/generation/createGenerationProofFailures.d.ts +3 -3
  46. package/lib/core/transform/generation/createGenerationProofFailures.js +11 -4
  47. package/lib/core/transform/generation/createGenerationProofFailures.js.map +1 -1
  48. package/lib/core/transform/generation/createGenerationProofFailures.mjs +11 -4
  49. package/lib/core/transform/generation/createGenerationProofFailures.mjs.map +1 -1
  50. package/lib/core/transform/generation/mergeGenerationProofFailures.d.cts +4 -4
  51. package/lib/core/transform/generation/mergeGenerationProofFailures.d.mts +4 -4
  52. package/lib/core/transform/generation/mergeGenerationProofFailures.d.ts +4 -4
  53. package/lib/core/transform/generation/mergeGenerationProofFailures.js +11 -4
  54. package/lib/core/transform/generation/mergeGenerationProofFailures.js.map +1 -1
  55. package/lib/core/transform/generation/mergeGenerationProofFailures.mjs +11 -4
  56. package/lib/core/transform/generation/mergeGenerationProofFailures.mjs.map +1 -1
  57. package/lib/core/transform/generation/recordGenerationProofFailure.d.cts +4 -4
  58. package/lib/core/transform/generation/recordGenerationProofFailure.d.mts +4 -4
  59. package/lib/core/transform/generation/recordGenerationProofFailure.d.ts +4 -4
  60. package/lib/core/transform/generation/recordGenerationProofFailure.js +8 -4
  61. package/lib/core/transform/generation/recordGenerationProofFailure.js.map +1 -1
  62. package/lib/core/transform/generation/recordGenerationProofFailure.mjs +8 -4
  63. package/lib/core/transform/generation/recordGenerationProofFailure.mjs.map +1 -1
  64. package/lib/core/transform/generation/selectTransformAttemptDisposition.d.cts +11 -7
  65. package/lib/core/transform/generation/selectTransformAttemptDisposition.d.mts +11 -7
  66. package/lib/core/transform/generation/selectTransformAttemptDisposition.d.ts +11 -7
  67. package/lib/core/transform/generation/selectTransformAttemptDisposition.js +11 -7
  68. package/lib/core/transform/generation/selectTransformAttemptDisposition.js.map +1 -1
  69. package/lib/core/transform/generation/selectTransformAttemptDisposition.mjs +11 -7
  70. package/lib/core/transform/generation/selectTransformAttemptDisposition.mjs.map +1 -1
  71. package/lib/core/transform/generation/transformProject.js +1 -0
  72. package/lib/core/transform/generation/transformProject.js.map +1 -1
  73. package/lib/core/transform/generation/transformProject.mjs +1 -0
  74. package/lib/core/transform/generation/transformProject.mjs.map +1 -1
  75. package/lib/core/transform/validation/TtscGenerationProof.d.cts +4 -1
  76. package/lib/core/transform/validation/TtscGenerationProof.d.mts +4 -1
  77. package/lib/core/transform/validation/TtscGenerationProof.d.ts +4 -1
  78. package/lib/core/transform/validation/TtscGenerationProof.js +4 -1
  79. package/lib/core/transform/validation/TtscGenerationProof.js.map +1 -1
  80. package/lib/core/transform/validation/TtscGenerationProof.mjs +4 -1
  81. package/lib/core/transform/validation/TtscGenerationProof.mjs.map +1 -1
  82. package/lib/core/transform/validation/captureExternalInputSnapshot.js +1 -1
  83. package/lib/core/transform/validation/captureExternalInputSnapshot.js.map +1 -1
  84. package/lib/core/transform/validation/captureExternalInputSnapshot.mjs +1 -1
  85. package/lib/core/transform/validation/captureExternalInputSnapshot.mjs.map +1 -1
  86. package/lib/core/transform/validation/captureUniversalHostInputValidation.js +1 -1
  87. package/lib/core/transform/validation/captureUniversalHostInputValidation.js.map +1 -1
  88. package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs +1 -1
  89. package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs.map +1 -1
  90. package/lib/core/transform/validation/compilerGraphInputProofFailures.js +1 -1
  91. package/lib/core/transform/validation/compilerGraphInputProofFailures.js.map +1 -1
  92. package/lib/core/transform/validation/compilerGraphInputProofFailures.mjs +1 -1
  93. package/lib/core/transform/validation/compilerGraphInputProofFailures.mjs.map +1 -1
  94. package/lib/core/transform/validation/matchesCachedSource.d.cts +4 -2
  95. package/lib/core/transform/validation/matchesCachedSource.d.mts +4 -2
  96. package/lib/core/transform/validation/matchesCachedSource.d.ts +4 -2
  97. package/lib/core/transform/validation/matchesCachedSource.js +6 -2
  98. package/lib/core/transform/validation/matchesCachedSource.js.map +1 -1
  99. package/lib/core/transform/validation/matchesCachedSource.mjs +6 -2
  100. package/lib/core/transform/validation/matchesCachedSource.mjs.map +1 -1
  101. package/lib/core/transform/watch/evidencedWatchInput.d.cts +1 -1
  102. package/lib/core/transform/watch/evidencedWatchInput.d.mts +1 -1
  103. package/lib/core/transform/watch/evidencedWatchInput.d.ts +1 -1
  104. package/lib/core/transform/watch/evidencedWatchInput.js +6 -2
  105. package/lib/core/transform/watch/evidencedWatchInput.js.map +1 -1
  106. package/lib/core/transform/watch/evidencedWatchInput.mjs +6 -2
  107. package/lib/core/transform/watch/evidencedWatchInput.mjs.map +1 -1
  108. package/package.json +3 -3
  109. package/src/core/transform/cache/TtscCachedProjectTransform.ts +24 -0
  110. package/src/core/transform/deliverCachedTransform.ts +5 -1
  111. package/src/core/transform/filesystem/matchesNativeCompilerSnapshotFilesystem.ts +31 -0
  112. package/src/core/transform/generation/TtscGenerationProofFailures.ts +21 -0
  113. package/src/core/transform/generation/canDeliverCompilerSnapshot.ts +50 -0
  114. package/src/core/transform/generation/captureTransformGeneration.ts +50 -13
  115. package/src/core/transform/generation/captureTransformSourceHashes.ts +19 -8
  116. package/src/core/transform/generation/compilerSnapshotFailureClassifier.ts +80 -0
  117. package/src/core/transform/generation/createGenerationProofFailures.ts +13 -4
  118. package/src/core/transform/generation/mergeGenerationProofFailures.ts +13 -4
  119. package/src/core/transform/generation/recordGenerationProofFailure.ts +8 -4
  120. package/src/core/transform/generation/selectTransformAttemptDisposition.ts +14 -7
  121. package/src/core/transform/generation/transformProject.ts +1 -0
  122. package/src/core/transform/validation/TtscGenerationProof.ts +4 -1
  123. package/src/core/transform/validation/captureExternalInputSnapshot.ts +3 -1
  124. package/src/core/transform/validation/captureUniversalHostInputValidation.ts +3 -1
  125. package/src/core/transform/validation/compilerGraphInputProofFailures.ts +3 -1
  126. package/src/core/transform/validation/matchesCachedSource.ts +7 -2
  127. package/src/core/transform/watch/evidencedWatchInput.ts +7 -2
@@ -66,6 +66,7 @@ export function deliverCachedTransform(props: {
66
66
  epoch,
67
67
  hooks,
68
68
  );
69
+ if (cached.snapshotDeliveryOnly === true) hooks?.markVolatile?.();
69
70
  reportSuccessDiagnostics(cached, epoch);
70
71
  let output;
71
72
  try {
@@ -90,7 +91,10 @@ export function deliverCachedTransform(props: {
90
91
  notifyVolatileDelivery(hooks, cached, file);
91
92
  return createTransformResult(file, source, output);
92
93
  } catch (error) {
93
- if (cached.freshDeliveryOnly === true)
94
+ if (
95
+ cached.freshDeliveryOnly === true ||
96
+ cached.snapshotDeliveryOnly === true
97
+ )
94
98
  evictGeneration(cache, key, generation);
95
99
  throw error;
96
100
  }
@@ -0,0 +1,31 @@
1
+ import { DEFAULT_FILESYSTEM_OPERATIONS } from "./DEFAULT_FILESYSTEM_OPERATIONS";
2
+ import type { TtscTransformFilesystemOperations } from "./TtscTransformFilesystemOperations";
3
+
4
+ /**
5
+ * Establish that a consumer observes the native input view its compiler used. A
6
+ * copied default table preserves that authority; substituted input operations
7
+ * have no equivalent-view certificate. Watch callbacks do not replace inputs.
8
+ *
9
+ * @evidence contracts/common.md#principled-implementation Every frozen native input capability must retain its reference and native path/case policy must remain selected; this connects the consumer view to native compiler reads before freshness-only delivery.
10
+ * @evidence contracts/common.md#clear-and-simple-design One predicate checks the existing operation table without adding a claimed-equivalence option or probing filesystem contents.
11
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Unknown wrappers and unavailable capabilities retain ordinary proof rather than borrowing native authority; no plugin, path or test identity determines admission.
12
+ * @evidence contracts/common.md#meaningful-documentation Prose distinguishes copied tables, substituted input operations and independent watch callbacks.
13
+ * @evidence contracts/portability.md#os-neutral-implementation Actual native operation references establish input semantics; an explicit path dialect must match the current process and a supplied case-policy implementation remains uncertified. No OS name establishes a volume's case behavior.
14
+ * @evidence contracts/performance.md#efficient-algorithms One fixed native-operation table is enumerated and references are compared; no input paths, source bytes or capabilities are queried.
15
+ * @evidence contracts/performance.md#reuse-equivalent-work The frozen default capabilities are borrowed across calls, while the supplied view is checked afresh without retaining a verdict across possible changes.
16
+ * @evidence contracts/performance.md#bound-retention-and-release-resources A fixed call-local entry array follows the synchronous comparison; no input history, callback ownership or native handle is retained.
17
+ */
18
+ export function matchesNativeCompilerSnapshotFilesystem(
19
+ filesystem: TtscTransformFilesystemOperations,
20
+ ): boolean {
21
+ if (
22
+ filesystem.caseSensitive !== undefined ||
23
+ (filesystem.platform !== undefined &&
24
+ filesystem.platform !== process.platform)
25
+ )
26
+ return false;
27
+ return Object.entries(DEFAULT_FILESYSTEM_OPERATIONS).every(
28
+ ([name, operation]) =>
29
+ filesystem[name as keyof TtscTransformFilesystemOperations] === operation,
30
+ );
31
+ }
@@ -24,6 +24,27 @@ export interface TtscGenerationProofFailures {
24
24
  /** Unique witnesses kept, at most `MAX_GENERATION_PROOF_FAILURES`. */
25
25
  entries: TtscGenerationProofFailure[];
26
26
 
27
+ /**
28
+ * Complete streaming classification, including witnesses omitted from
29
+ * diagnostics.
30
+ */
31
+ snapshotCompatible?: boolean;
32
+
33
+ /**
34
+ * Borrowed generation-owned classifier, absent without a captured native
35
+ * view.
36
+ *
37
+ * @evidence contracts/common.md#principled-implementation The sticky compatibility verdict accounts for every occurrence before diagnostic truncation; after its first refusal no later occurrence can restore delivery authority.
38
+ * @evidence contracts/common.md#clear-and-simple-design Collectors borrow one generation classifier rather than rebuilding its recorded-input index.
39
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The callback records compatibility only; callers still require complete producer proof and never infer cache freshness from it.
40
+ * @evidence contracts/common.md#meaningful-documentation The member states optionality and ownership, while the generation classifier documents actual path and kind admission.
41
+ * @evidence contracts/portability.md#os-neutral-implementation The callback receives native lexical witness paths and delegates their interpretation to the generation's classifier.
42
+ * @evidenceExclude contracts/performance.md#efficient-algorithms This signature declares no runtime computation; the classifier implementation owns its index and lookup costs.
43
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work This signature declares no memo; generation capture owns sharing the callback.
44
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources This signature acquires no resource; generation capture owns the borrowed closure's lifetime.
45
+ */
46
+ snapshotFailureClassifier?: (failure: TtscGenerationProofFailure) => boolean;
47
+
27
48
  /** Saturated count of further witness occurrences dropped after the bound. */
28
49
  omitted: number;
29
50
 
@@ -0,0 +1,50 @@
1
+ import type { ITtscCompilerTransformation } from "ttsc";
2
+
3
+ import { resultFilesystem } from "../cache/resultFilesystem";
4
+ import { matchesNativeCompilerSnapshotFilesystem } from "../filesystem/matchesNativeCompilerSnapshotFilesystem";
5
+ import type { TtscGenerationProofFailures } from "./TtscGenerationProofFailures";
6
+ import { compilerSnapshotFailureClassifier } from "./compilerSnapshotFailureClassifier";
7
+
8
+ /**
9
+ * Separate a coherent local compiler result from proof that disk still matches
10
+ * it. Only recorded compiler inputs and project changes may lose freshness;
11
+ * missing, contradictory or unobserved producer inputs remain refusals. Adopted
12
+ * results must be current on this worker before they can be delivered. The
13
+ * consumer must retain the native input view; a substituted filesystem cannot
14
+ * classify its disagreement with the compiler as a physical source edit.
15
+ *
16
+ * @evidence contracts/common.md#principled-implementation A native shared snapshot ID, matching native consumer input capabilities, internally consistent graph and complete host observation establish current-generation authority; only explicit freshness changes covered by that graph can bypass stabilization.
17
+ * @evidence contracts/common.md#clear-and-simple-design One admission predicate separates delivery from existing cache/publication validation without weakening those validators.
18
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Unknown failure kinds, incomplete reports, foreign adoptions and producer conflicts cannot become a successful snapshot delivery.
19
+ * @evidence contracts/common.md#meaningful-documentation Prose distinguishes local authority, disk freshness and adopted-worker requirements.
20
+ * @evidence contracts/portability.md#os-neutral-implementation Native path.resolve maps compiler-relative proof keys to their project anchor; the consumer gate compares actual native input capabilities and explicit path grammar; this predicate infers no case or physical identity from OS names.
21
+ * @evidence contracts/performance.md#efficient-algorithms A fixed native capability comparison establishes the observing view before any summary is trusted. A captured streaming summary then answers without another scan; legacy caller aggregates with no omissions use one recorded-input classifier and a bounded witness scan. Native disk inputs are not reread.
22
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work Delivery permission does not grant cache or publication reuse and is recomputed for each captured result.
23
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Call-local indexes retain no handle or generation history.
24
+ */
25
+ export function canDeliverCompilerSnapshot(props: {
26
+ result: ITtscCompilerTransformation;
27
+ projectRoot: string;
28
+ failures: TtscGenerationProofFailures;
29
+ adopted: boolean;
30
+ }): boolean {
31
+ const { result, failures } = props;
32
+ if (
33
+ props.adopted ||
34
+ result.type !== "success" ||
35
+ !result.graph?.compilationSnapshot ||
36
+ !matchesNativeCompilerSnapshotFilesystem(resultFilesystem(result)) ||
37
+ result.observationsComplete === false ||
38
+ Object.keys(result.hostInputProofFailures ?? {}).length !== 0 ||
39
+ Object.keys(result.graph.inputProofFailures ?? {}).length !== 0 ||
40
+ failures.entries.length === 0
41
+ )
42
+ return false;
43
+ if (failures.snapshotCompatible !== undefined)
44
+ return failures.snapshotCompatible;
45
+ const classify = compilerSnapshotFailureClassifier(
46
+ result,
47
+ props.projectRoot,
48
+ )!;
49
+ return failures.omitted === 0 && failures.entries.every(classify);
50
+ }
@@ -12,6 +12,8 @@ import { TRANSFORM_RESULT_MEMBERSHIP } from "../cache/TRANSFORM_RESULT_MEMBERSHI
12
12
  import type { TtscCachedProjectTransform } from "../cache/TtscCachedProjectTransform";
13
13
  import { refreshFilesystemClockReference } from "../clock/refreshFilesystemClockReference";
14
14
  import { reportDivergentDelivery } from "../diagnostics/reportDivergentDelivery";
15
+ import { envelopeDerivation } from "../envelope/envelopeDerivation";
16
+ import { envelopeGraphIndexes } from "../envelope/envelopeGraphIndexes";
15
17
  import { generationCaseSensitivity } from "../envelope/generationCaseSensitivity";
16
18
  import { selectDeclaredProjectInputKeys } from "../envelope/selectDeclaredProjectInputKeys";
17
19
  import { selectExternalInputPaths } from "../envelope/selectExternalInputPaths";
@@ -49,8 +51,10 @@ import { witnessExternalDependencies } from "../validation/witnessExternalDepend
49
51
  import { TRANSFORM_FAILED_GENERATION_VALIDATIONS } from "./TRANSFORM_FAILED_GENERATION_VALIDATIONS";
50
52
  import { TRANSFORM_GENERATION_FAILURES } from "./TRANSFORM_GENERATION_FAILURES";
51
53
  import type { TtscCompilerMembershipHint } from "./TtscCompilerMembershipHint";
54
+ import { canDeliverCompilerSnapshot } from "./canDeliverCompilerSnapshot";
52
55
  import { captureFailedGenerationInputStates } from "./captureFailedGenerationInputStates";
53
56
  import { captureTransformSourceHashes } from "./captureTransformSourceHashes";
57
+ import { compilerSnapshotFailureClassifier } from "./compilerSnapshotFailureClassifier";
54
58
  import { createGenerationProofFailures } from "./createGenerationProofFailures";
55
59
  import { mergeGenerationProofFailures } from "./mergeGenerationProofFailures";
56
60
  import { primeCompilerMembership } from "./primeCompilerMembership";
@@ -655,8 +659,9 @@ export async function captureTransformGeneration(props: {
655
659
  hostInputTracker,
656
660
  candidateTracker,
657
661
  );
658
- // The compile read this file from disk, so the disk's bytes are its state in
659
- // this generation. A delivered text that differs, because a plugin ordered
662
+ // Ordinary stable captures use the disk baseline below; snapshot-only
663
+ // delivery later replaces it with the compiler's captured source hash.
664
+ // Delivered text that differs, because a plugin ordered
660
665
  // before ttsc rewrote the module or the file changed after the host read
661
666
  // it, must not replace them: every sibling delivery compares the disk and
662
667
  // would recompile the project (samchon/ttsc#1394). An actual delivery is reported once
@@ -711,21 +716,15 @@ export async function captureTransformGeneration(props: {
711
716
  ? {}
712
717
  : { temporaryTsconfig: envelopeTemporaryTsconfig }),
713
718
  };
719
+ cached.snapshotFailureClassifier = compilerSnapshotFailureClassifier(
720
+ result,
721
+ projectRoot,
722
+ );
714
723
  cached.sourceHashes = captureTransformSourceHashes(
715
724
  cached,
716
725
  props.currentFile,
717
726
  diskHash ?? deliveredHash,
718
727
  );
719
- // Preparation reads native source only to seed the ordinary capture. A
720
- // later edit is handled by generation proof, not a warning about a host
721
- // rewrite: no host delivered that speculative module (#1764).
722
- if (
723
- props.reportDivergence !== false &&
724
- diskHash !== undefined &&
725
- diskHash !== deliveredHash
726
- ) {
727
- reportDivergentDelivery(cached, props.currentFile);
728
- }
729
728
  // An adopted compile was certified by its publisher, and is matched below
730
729
  // against the state that publisher recorded.
731
730
  const externalInputSnapshot = captureExternalInputSnapshot(
@@ -764,7 +763,9 @@ export async function captureTransformGeneration(props: {
764
763
  // Evaluate every proof family rather than short-circuiting after the first
765
764
  // failed one, so a rejected generation reports every missing premise. The
766
765
  // same checks establish a successful generation's reuse authority.
767
- const failures = createGenerationProofFailures();
766
+ const failures = createGenerationProofFailures(
767
+ cached.snapshotFailureClassifier,
768
+ );
768
769
  if (!configStable) {
769
770
  recordGenerationProofFailure(failures, {
770
771
  domain: "project",
@@ -828,6 +829,33 @@ export async function captureTransformGeneration(props: {
828
829
  externalInputSnapshot.complete &&
829
830
  adoptionFailure === undefined &&
830
831
  universalInputs;
832
+ const snapshotDeliveryOnly =
833
+ !stableProjectSnapshot &&
834
+ canDeliverCompilerSnapshot({
835
+ result,
836
+ projectRoot,
837
+ failures,
838
+ adopted: adopted !== undefined,
839
+ });
840
+ const capturedSource = snapshotDeliveryOnly
841
+ ? envelopeGraphIndexes(
842
+ envelopeDerivation(cached),
843
+ cached,
844
+ ).inputObservations.get(path.resolve(props.currentFile))?.readFile
845
+ : undefined;
846
+ // A source save between the compiler read and the postcompile walk is not
847
+ // proof of an earlier host rewrite. For a raced snapshot, report one only
848
+ // when the compiler and disk still agree on this module's source content.
849
+ if (
850
+ props.reportDivergence !== false &&
851
+ diskHash !== undefined &&
852
+ diskHash !== deliveredHash &&
853
+ (!snapshotDeliveryOnly ||
854
+ (before.hashes[currentFileKey] === diskHash &&
855
+ capturedSource?.ok === true &&
856
+ capturedSource.hash === diskHash))
857
+ )
858
+ reportDivergentDelivery(cached, props.currentFile);
831
859
  // An adopted envelope failed either because the publication does not hold
832
860
  // on this disk or because this worker's own window moved around it, and
833
861
  // only the first speaks against the publication (samchon/ttsc#1479). The
@@ -977,6 +1005,15 @@ export async function captureTransformGeneration(props: {
977
1005
  });
978
1006
  }
979
1007
  cached.projectSnapshotComplete = stableProjectSnapshot;
1008
+ cached.snapshotDeliveryOnly = snapshotDeliveryOnly;
1009
+ if (cached.snapshotDeliveryOnly && props.deliveryEpoch !== undefined)
1010
+ cached.passDeliveryOnly = true;
1011
+ if (cached.snapshotDeliveryOnly)
1012
+ cached.sourceHashes = captureTransformSourceHashes(
1013
+ cached,
1014
+ props.currentFile,
1015
+ diskHash ?? deliveredHash,
1016
+ );
980
1017
  // Attach notifications only while they can actually prove membership. A
981
1018
  // generation that could not open its watchers keeps its recorded snapshot
982
1019
  // and validates through it, rather than losing the cache entirely.
@@ -8,22 +8,24 @@ import { hostInputStateHash } from "../inputs/hostInputStateHash";
8
8
 
9
9
  /**
10
10
  * Capture native host-state hashes for source paths named by transform outputs,
11
- * including sources outside the project walk. Reads hash raw bytes; a failed
12
- * read of an observed directory retains the host-state directory marker, while
13
- * other unreadable output paths remain absent.
11
+ * including sources outside the project walk. Snapshot-only delivery instead
12
+ * preserves the compiler's recorded hash where available. Ordinary reads hash
13
+ * raw bytes; a failed read of an observed directory retains the host-state
14
+ * directory marker, while other unreadable output paths remain absent.
14
15
  *
15
16
  * The current source identity is then overwritten with the caller's selected
16
17
  * hash even when no output names it. Capture supplies its post-compile project
17
18
  * walk's disk hash when available and otherwise the delivered-text hash; that
18
19
  * fallback does not establish that the compiler observed those bytes. If the
19
- * output pass already read this source, the final assignment does not undo it.
20
+ * output pass already recorded this source for snapshot-only delivery, the
21
+ * compiler's hash keeps precedence over the caller fallback.
20
22
  *
21
- * @evidence contracts/common.md#principled-implementation Successful output keys identify source paths relative to the project; native host-state hashes become identity-keyed baselines and the caller's selected disk-or-delivery hash overrides the current identity without granting generation completeness.
23
+ * @evidence contracts/common.md#principled-implementation Successful output keys identify source paths relative to the project; native host-state hashes become identity-keyed baselines and the caller's selected disk-or-delivery hash overrides the current identity for ordinary delivery, while snapshot-only delivery preserves captured compiler hashes without granting generation completeness.
22
24
  * @evidence contracts/common.md#clear-and-simple-design This helper constructs only the source baseline map; resultFilesystem supplies native reads and envelopeDerivation supplies the generation's shared identity context.
23
25
  * @evidence contracts/common.md#prohibited-implementation-shortcuts Non-directory failed reads supply no fabricated output-source hash, and transformed output text is never hashed as source. The explicitly supplied current-source fallback is distinguished from native disk evidence; the capture owner separately decides completeness and reuse.
24
26
  * @evidence contracts/common.md#meaningful-documentation Native paragraphs distinguish raw host state, directory markers and failed reads from the current source's caller-selected fallback and explain the output-pass read that an override cannot avoid.
25
27
  * @evidence contracts/portability.md#os-neutral-implementation Output paths are resolved with Node native semantics and compared through the envelope identity context; no case folding or OS-specific file reader is introduced.
26
- * @evidence contracts/performance.md#efficient-algorithms Object.keys allocates the full output-key array, then one pass resolves native spellings, reads and hashes each exposed source's bytes and inserts successful host states. Failed reads may stat; identity resolution may observe uncached ancestors and case capabilities. Distinct output spellings may repeat a physical read before sharing one key. Map storage grows with distinct identities and key text; the final current assignment adds no read beyond that pass.
28
+ * @evidence contracts/performance.md#efficient-algorithms Object.keys allocates the full output-key array, then one pass resolves native spellings and inserts compiler-recorded hashes for snapshot-only delivery, otherwise reading and hashing each exposed source's bytes for host state. Failed reads may stat; identity resolution may observe uncached ancestors and case capabilities. Distinct output spellings may repeat a physical read before sharing one key. Map storage grows with distinct identities and key text; the final current assignment adds no read beyond that pass.
27
29
  * @evidence contracts/performance.md#reuse-equivalent-work The caller's selected current hash and the immutable envelope's identity transaction are reused; the output pass does not memoize content reads by physical identity. The fresh map belongs to this capture rather than reusing historical content across changes.
28
30
  * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Generation capture owns the returned baseline map's lifetime; this helper acquires no retained handle or observer.
29
31
  */
@@ -41,10 +43,19 @@ export function captureTransformSourceHashes(
41
43
  if (cached.result.type === "success") {
42
44
  for (const output of Object.keys(cached.result.typescript)) {
43
45
  const file = path.resolve(cached.projectRoot, output);
44
- const hash = hostInputStateHash(file, filesystem);
46
+ const hash =
47
+ cached.snapshotDeliveryOnly === true &&
48
+ Object.hasOwn(cached.result.graph?.inputHashes ?? {}, output)
49
+ ? (cached.result.graph!.inputHashes![output] ?? null)
50
+ : hostInputStateHash(file, filesystem);
45
51
  if (hash !== null) hashes[pathIdentityKey(file, identities)] = hash;
46
52
  }
47
53
  }
48
- hashes[pathIdentityKey(currentFile, identities)] = currentSourceHash;
54
+ const currentIdentity = pathIdentityKey(currentFile, identities);
55
+ if (
56
+ cached.snapshotDeliveryOnly !== true ||
57
+ hashes[currentIdentity] === undefined
58
+ )
59
+ hashes[currentIdentity] = currentSourceHash;
49
60
  return hashes;
50
61
  }
@@ -0,0 +1,80 @@
1
+ import path from "node:path";
2
+ import type { ITtscCompilerTransformation } from "ttsc";
3
+
4
+ import type { TtscGenerationProofFailure } from "./TtscGenerationProofFailure";
5
+
6
+ /**
7
+ * Index one native snapshot's recorded inputs for streaming freshness
8
+ * classification. The diagnostic witness limit must not decide whether a
9
+ * compilation is coherent, so compatibility is decided before diagnostic
10
+ * truncation and remains refused after the first incompatible occurrence.
11
+ *
12
+ * @evidence contracts/common.md#principled-implementation Only explicit freshness changes to recorded compiler inputs or project discovery qualify; changed configuration selection and conflicting host/compiler reads do not; missing and contradictory producer evidence stays outside this class.
13
+ * @evidence contracts/common.md#clear-and-simple-design One generation-owned classifier is shared by its proof collectors and final delivery admission.
14
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No failure is ignored because its printable witness exceeded the diagnostic limit; unknown kinds and unrecorded plugin inputs remain refusals.
15
+ * @evidence contracts/common.md#meaningful-documentation Prose explains streaming classification, diagnostic truncation and generation ownership.
16
+ * @evidence contracts/portability.md#os-neutral-implementation Native path.resolve anchors protocol input names without guessing physical identity or case behavior.
17
+ * @evidence contracts/performance.md#efficient-algorithms Compiler observation and host hash indexes cost recorded path bytes and input counts; each failure uses a kind check and indexed lexical lookup.
18
+ * @evidence contracts/performance.md#reuse-equivalent-work Every collector for this generation borrows the same classifier and recorded-input index; another generation constructs its own view.
19
+ * @evidence contracts/performance.md#bound-retention-and-release-resources The generation owns its path index and closure until eviction or disposal releases the generation; retained paths follow the reported input population with no separate handle.
20
+ */
21
+ export function compilerSnapshotFailureClassifier(
22
+ result: ITtscCompilerTransformation,
23
+ projectRoot: string,
24
+ ): ((failure: TtscGenerationProofFailure) => boolean) | undefined {
25
+ if (result.type !== "success" || !result.graph?.compilationSnapshot)
26
+ return undefined;
27
+ const recorded = new Map(
28
+ Object.entries(result.graph.inputObservations ?? {}).map(
29
+ ([file, observation]) => [path.resolve(projectRoot, file), observation],
30
+ ),
31
+ );
32
+ const hostHashes = new Map(
33
+ Object.entries(result.hostInputHashes ?? {}).map(([file, hash]) => [
34
+ path.resolve(projectRoot, file),
35
+ hash,
36
+ ]),
37
+ );
38
+ const freshnessKinds = new Set([
39
+ "content-changed",
40
+ "realpath-changed",
41
+ "graph-content-changed",
42
+ "graph-realpath-changed",
43
+ "accessible-entries-changed",
44
+ "file-exists-changed",
45
+ "directory-exists-changed",
46
+ "stat-changed",
47
+ "read-file-changed",
48
+ "native-file-changed",
49
+ "native-directory-changed",
50
+ "native-entry-changed",
51
+ "native-optional-file-changed",
52
+ "input-content-changed",
53
+ "input-metadata-changed",
54
+ "directory-membership-changed",
55
+ "directory-changed-during-walk",
56
+ "file-changed-during-read",
57
+ "project-membership-event",
58
+ "membership-policy-learned",
59
+ "snapshot-mismatch",
60
+ "changed-during-validation",
61
+ ]);
62
+ return (failure) => {
63
+ if (!freshnessKinds.has(failure.kind)) return false;
64
+ if (failure.domain === "project") return true;
65
+ if (failure.path === undefined) return false;
66
+ const file = path.resolve(failure.path);
67
+ const observation = recorded.get(file);
68
+ if (observation === undefined) return false;
69
+ // A descriptor/host read must agree with the compiler's captured text.
70
+ // Merely sharing a path cannot make two different evaluation epochs coherent.
71
+ if (failure.domain === "host" && hostHashes.has(file)) {
72
+ const read = observation.readFile;
73
+ return (
74
+ read !== undefined &&
75
+ hostHashes.get(file) === (read.ok ? read.hash : null)
76
+ );
77
+ }
78
+ return true;
79
+ };
80
+ }
@@ -4,15 +4,24 @@ import type { TtscGenerationProofFailures } from "./TtscGenerationProofFailures"
4
4
  * Create a fresh proof-witness collection for one transform attempt. Its
5
5
  * recorder bounds retained entries and their deduplication identities.
6
6
  *
7
- * @evidence contracts/common.md#principled-implementation Empty entries, zero omitted occurrences and an empty seen set establish the recorder's initial aggregate invariants.
7
+ * @evidence contracts/common.md#principled-implementation Empty entries, zero omitted occurrences and an empty seen set establish the recorder's initial aggregate invariants. The optional generation classifier records complete freshness compatibility before diagnostic truncation.
8
8
  * @evidence contracts/common.md#clear-and-simple-design This constructor supplies only fresh aggregate storage; the recorder owns limits and identity composition.
9
9
  * @evidence contracts/common.md#prohibited-implementation-shortcuts An attempt receives independent storage rather than sharing mutable witnesses from an earlier compile or manufacturing an initial verdict.
10
10
  * @evidence contracts/common.md#meaningful-documentation Native prose identifies per-attempt ownership and the recorder's bounding responsibility before separated acknowledgments.
11
- * @evidence contracts/performance.md#bound-retention-and-release-resources Fresh storage transfers to the attempt owner and its terminal diagnostic sequence; recordGenerationProofFailure bounds entry and identity counts at eight, while retained witness text follows supplied lengths. This constructor owns no handle or separate historical collection.
11
+ * @evidence contracts/performance.md#bound-retention-and-release-resources Fresh storage transfers to the attempt owner and its terminal diagnostic sequence; recordGenerationProofFailure bounds entry and identity counts at eight, while retained witness text follows supplied lengths. This constructor owns no handle or separate historical collection. The optional borrowed classifier keeps its generation input indexes reachable while either the generation or aggregate retains it; those indexes are not subject to the diagnostic witness bound.
12
12
  * @evidenceExclude contracts/performance.md#efficient-algorithms Allocates an empty collection.
13
13
  * @evidenceExclude contracts/performance.md#reuse-equivalent-work Creates a new collection per attempt by definition.
14
14
  * @evidenceExclude contracts/portability.md#os-neutral-implementation Allocates an empty collection and reads no filesystem or path.
15
15
  */
16
- export function createGenerationProofFailures(): TtscGenerationProofFailures {
17
- return { entries: [], omitted: 0, seen: new Set() };
16
+ export function createGenerationProofFailures(
17
+ snapshotFailureClassifier?: TtscGenerationProofFailures["snapshotFailureClassifier"],
18
+ ): TtscGenerationProofFailures {
19
+ return {
20
+ entries: [],
21
+ omitted: 0,
22
+ seen: new Set(),
23
+ ...(snapshotFailureClassifier === undefined
24
+ ? {}
25
+ : { snapshotFailureClassifier, snapshotCompatible: true }),
26
+ };
18
27
  }
@@ -10,19 +10,19 @@ import { recordGenerationProofFailure } from "./recordGenerationProofFailure";
10
10
  * unchanged. Retained witnesses are shared references, so producers must treat
11
11
  * their classifications as fixed after recording.
12
12
  *
13
- * @evidence contracts/common.md#principled-implementation Retained source entries use the target recorder's identity policy, while saturated addition preserves already omitted occurrence counts that cannot be recovered from source entries.
13
+ * @evidence contracts/common.md#principled-implementation Retained source entries use the target recorder's identity policy, while saturated addition preserves already omitted occurrence counts that cannot be recovered from source entries. A positive omitted-witness summary transfers only under the same generation classifier; refusal remains sticky before diagnostic truncation.
14
14
  * @evidence contracts/common.md#clear-and-simple-design This operation coordinates aggregation without duplicating recorder limits or witness identity encoding.
15
15
  * @evidence contracts/common.md#prohibited-implementation-shortcuts Missing witnesses remain omitted rather than being silently converted into proof success or guessed unique identities.
16
16
  * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain shared recorder ownership and the reason lost source identities cannot be deduplicated.
17
17
  * @evidence contracts/performance.md#efficient-algorithms
18
18
  * Merge visits the source's recorder-bounded retained entries once. Each
19
19
  * delegated insertion encodes the complete witness tuple and queries its
20
- * identity, so work and temporary encoded keys retain witness-text cost even
20
+ * identity and optionally classifies lexical paths, so work and temporary encoded keys retain witness-text cost even
21
21
  * with at most eight entries. Omission addition is constant work; discarded
22
22
  * evidence is not reconstructed.
23
23
  * @evidence contracts/performance.md#reuse-equivalent-work The shared recorder reuses retained target identities to suppress duplicates across evidence families; mutable aggregate merges are not memoized.
24
- * @evidence contracts/performance.md#bound-retention-and-release-resources The target remains subject to the recorder's eight-entry/seen-key bound; merge retains no source history beyond copied witnesses and its saturated omission count.
25
- * @evidenceExclude contracts/portability.md#os-neutral-implementation Combines in-memory witness collections; it parses no path.
24
+ * @evidence contracts/performance.md#bound-retention-and-release-resources The target remains subject to the recorder's eight-entry/seen-key bound; merge retains no source history beyond copied witnesses and its saturated omission count. The optional borrowed classifier keeps its generation input indexes reachable while either the generation or aggregate retains it; those indexes are not subject to the diagnostic witness bound.
25
+ * @evidence contracts/portability.md#os-neutral-implementation Combines in-memory witnesses through the recorder, whose optional generation classifier owns native lexical path resolution.
26
26
  */
27
27
  export function mergeGenerationProofFailures(
28
28
  target: TtscGenerationProofFailures,
@@ -31,6 +31,15 @@ export function mergeGenerationProofFailures(
31
31
  for (const failure of source.entries) {
32
32
  recordGenerationProofFailure(target, failure);
33
33
  }
34
+ if (
35
+ target.snapshotFailureClassifier !== undefined &&
36
+ (source.snapshotCompatible === false ||
37
+ (source.omitted !== 0 &&
38
+ (source.snapshotCompatible !== true ||
39
+ source.snapshotFailureClassifier !==
40
+ target.snapshotFailureClassifier)))
41
+ )
42
+ target.snapshotCompatible = false;
34
43
  target.omitted = Math.min(
35
44
  Number.MAX_SAFE_INTEGER,
36
45
  target.omitted + source.omitted,
@@ -10,19 +10,23 @@ const MAX_GENERATION_PROOF_FAILURES = 8;
10
10
  * full, new occurrences increment a saturated omitted count; dropped identities
11
11
  * are not retained, so later repetitions of a dropped witness count again.
12
12
  *
13
- * @evidence contracts/common.md#principled-implementation A JSON tuple of domain, kind, path and detail defines witness identity, seen deduplicates retained entries and the entry bound plus saturated omitted counter represent evidence loss explicitly.
13
+ * @evidence contracts/common.md#principled-implementation A JSON tuple of domain, kind, path and detail defines witness identity, seen deduplicates retained entries and the entry bound plus saturated omitted counter represent evidence loss explicitly. The optional generation classifier records complete freshness compatibility before diagnostic truncation.
14
14
  * @evidence contracts/common.md#clear-and-simple-design One recorder owns identity, retained bounds and omission accounting so merge and capture callers share the same aggregate policy.
15
15
  * @evidence contracts/common.md#prohibited-implementation-shortcuts The eight-entry bound limits diagnostic storage rather than changing the proof verdict; omitted remains visible and no discarded witness is certified irrelevant.
16
16
  * @evidence contracts/common.md#meaningful-documentation Native paragraphs state retained duplicate handling and the dropped-occurrence limitation, while the internal comment explains why seen shares the storage bound.
17
- * @evidence contracts/performance.md#efficient-algorithms Identity encoding costs the witness text length and Set membership is direct; insertion touches one entry without rescanning the aggregate.
17
+ * @evidence contracts/performance.md#efficient-algorithms Identity encoding costs the witness text length and Set membership is direct; insertion touches one entry without rescanning the aggregate. Optional classification adds the generation classifier's lexical path lookup for each occurrence.
18
18
  * @evidence contracts/performance.md#reuse-equivalent-work Retained seen keys prevent repeated insertion of the same printable witness; dropped identities intentionally are not shared because doing so would require unbounded storage.
19
- * @evidence contracts/performance.md#bound-retention-and-release-resources Entries and seen retain at most eight witnesses/keys per attempt, and omitted saturates at MAX_SAFE_INTEGER; text bytes depend on producer witness lengths rather than a claimed byte-size bound.
20
- * @evidenceExclude contracts/portability.md#os-neutral-implementation Stores the path strings it is given inside a JSON identity key without parsing or comparing them as paths.
19
+ * @evidence contracts/performance.md#bound-retention-and-release-resources Entries and seen retain at most eight witnesses/keys per attempt, and omitted saturates at MAX_SAFE_INTEGER; text bytes depend on producer witness lengths rather than a claimed byte-size bound. The optional borrowed classifier keeps its generation input indexes reachable while either the generation or aggregate retains it; those indexes are not subject to the diagnostic witness bound.
20
+ * @evidence contracts/portability.md#os-neutral-implementation Witness identity preserves supplied strings; optional freshness classification delegates native lexical path resolution to the generation classifier.
21
21
  */
22
22
  export function recordGenerationProofFailure(
23
23
  failures: TtscGenerationProofFailures,
24
24
  failure: TtscGenerationProofFailure,
25
25
  ): void {
26
+ if (failures.snapshotFailureClassifier !== undefined)
27
+ failures.snapshotCompatible =
28
+ failures.snapshotCompatible === true &&
29
+ failures.snapshotFailureClassifier(failure);
26
30
  const key = JSON.stringify([
27
31
  failure.domain,
28
32
  failure.kind,
@@ -7,13 +7,15 @@ import { onlyLearnedCompileFacts } from "./onlyLearnedCompileFacts";
7
7
  * Select how one completed capture spends the retry owner's budgets. Supplied
8
8
  * facts describe the capture; this policy performs no capture or native proof.
9
9
  *
10
- * Coherent results return first. A local, lossless host-observation refusal can
11
- * transfer an incomplete local success. TtscGenerationProof owns any sharing of
12
- * its first module deliveries inside an explicit nonwatching pass; this policy
13
- * grants no independent native or persistent proof. Rejected attempts spend
14
- * movement only when they neither refute a publication nor solely learn facts.
15
- * Two movements or four captures stop retrying, retaining a current diagnostic
16
- * rather than a terminal instability verdict when its config is not refuted.
10
+ * Coherent results, including admitted current compiler snapshots, return
11
+ * first. Snapshot delivery does not spend disk-stabilization retries or grant
12
+ * future reuse. A local, lossless host-observation refusal can transfer an
13
+ * incomplete local success. TtscGenerationProof owns any sharing of its first
14
+ * module deliveries inside an explicit nonwatching pass; this policy grants no
15
+ * independent native or persistent proof. Rejected attempts spend movement only
16
+ * when they neither refute a publication nor solely learn facts. Two movements
17
+ * or four captures stop retrying, retaining a current diagnostic rather than a
18
+ * terminal instability verdict when its config is not refuted.
17
19
  *
18
20
  * The caller owns learned dependency/case carry, terminal validation, capture
19
21
  * disposal and result transfer. Selecting terminal does not certify a baseline
@@ -56,6 +58,9 @@ export function selectTransformAttemptDisposition(props: {
56
58
  /** Explicit config coherence; undefined retains the existing admission rule. */
57
59
  configStateComplete?: boolean;
58
60
 
61
+ /** Current compiler snapshot authority, independent of disk/cache freshness. */
62
+ snapshotDeliveryOnly?: boolean;
63
+
59
64
  /** Reusable project success proof, required explicitly for success acceptance. */
60
65
  projectSnapshotComplete?: boolean;
61
66
 
@@ -101,6 +106,8 @@ export function selectTransformAttemptDisposition(props: {
101
106
  moved: number;
102
107
  rejected: string | undefined;
103
108
  } {
109
+ if (props.resultType === "success" && props.snapshotDeliveryOnly === true)
110
+ return { kind: "accepted", freshDeliveryOnly: false };
104
111
  const freshDeliveryOnly =
105
112
  props.resultType === "failure" &&
106
113
  (props.observationsComplete === false ||
@@ -181,6 +181,7 @@ export async function transformProject(props: {
181
181
  const disposition = selectTransformAttemptDisposition({
182
182
  resultType: cached.result.type,
183
183
  configStateComplete: cached.configStateComplete,
184
+ snapshotDeliveryOnly: cached.snapshotDeliveryOnly,
184
185
  projectSnapshotComplete: cached.projectSnapshotComplete,
185
186
  projectHeldStill: cached.projectHeldStill,
186
187
  observationsComplete:
@@ -24,10 +24,13 @@ import type { TtscTransformHooks } from "../watch/TtscTransformHooks";
24
24
  * persistent/repeated deliveries require new current observations. Incomplete
25
25
  * observations can share a coherent local result only inside an explicitly
26
26
  * nonwatching pass with actual host-cache withdrawal, never a record or pool.
27
+ * Captured native snapshots separately permit first deliveries in their
28
+ * original pass, including watching, without claiming disk freshness or future
29
+ * reuse.
27
30
  *
28
31
  * @evidence contracts/common.md#principled-implementation Explicit pass identity, source baseline and first-delivery membership delimit sharing; synchronous transactions independently qualify current native inputs and incomplete local outputs retain stricter lifecycle admission.
29
32
  * @evidence contracts/common.md#clear-and-simple-design One core owner supplies the same preparation, pass and fresh-only policies to every adapter instead of separate host-specific caches.
30
- * @evidence contracts/common.md#prohibited-implementation-shortcuts Missing observation never becomes complete snapshot authority; watching, persistent, repeated and unknown boundaries cannot borrow an incomplete pass result.
33
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Missing observation never becomes complete snapshot authority; watching cannot borrow an observer-unavailable pass result, and persistent, repeated and unknown boundaries cannot borrow either kind of pass-only result.
31
34
  * @evidence contracts/common.md#meaningful-documentation Native context names the four lifetimes and warns against the specific performance and stale-cache regressions they prevent.
32
35
  * @evidenceExclude contracts/portability.md#os-neutral-implementation Members delegate native observations to the generation's filesystem and the native environment owner.
33
36
  * @evidenceExclude contracts/performance.md#efficient-algorithms Members own baseline lookup, batch qualification and admission.
@@ -126,7 +126,9 @@ export function captureExternalInputSnapshot(
126
126
  > = {};
127
127
  const realpaths: Record<string, string | null> = {};
128
128
  const signatures: Record<string, string> = {};
129
- const failures = createGenerationProofFailures();
129
+ const failures = createGenerationProofFailures(
130
+ cached.snapshotFailureClassifier,
131
+ );
130
132
  const dependencies: string[] = [];
131
133
  const reported = new Set<string>();
132
134
  if (cached.result.type !== "exception") {
@@ -57,7 +57,9 @@ export function captureUniversalHostInputValidation(
57
57
  } {
58
58
  const filesystem = resultFilesystem(cached.result);
59
59
  const state = envelopeDerivation(cached);
60
- const failures = createGenerationProofFailures();
60
+ const failures = createGenerationProofFailures(
61
+ cached.snapshotFailureClassifier,
62
+ );
61
63
  const validation: TtscHostInputValidation = {
62
64
  entries: new Map(),
63
65
  covered: new Set(),
@@ -34,7 +34,9 @@ import { isTransformScratchInput } from "../tsconfig/isTransformScratchInput";
34
34
  export function compilerGraphInputProofFailures(
35
35
  cached: TtscCachedProjectTransform,
36
36
  ): TtscGenerationProofFailures {
37
- const failures = createGenerationProofFailures();
37
+ const failures = createGenerationProofFailures(
38
+ cached.snapshotFailureClassifier,
39
+ );
38
40
  if (
39
41
  cached.result.type === "exception" ||
40
42
  cached.result.graph === undefined ||