ttsc 0.31.0 → 0.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/platform/main.go +2 -2
- package/internal/sourceprocess/contain_windows.go +10 -13
- package/internal/sourceprocess/started_windows.go +41 -0
- package/internal/sourceprocess/windows_started_publication_distinguishes_pending_from_refusal_test.go +76 -0
- package/internal/watchhelper/run.go +30 -20
- package/internal/watchhelper/run_other.go +4 -4
- package/internal/watchhelper/run_windows.go +471 -0
- package/internal/watchhelper/watchhelper.go +8 -2
- package/internal/watchhelper/windows_notifications_preserve_mutations_without_access_noise_test.go +506 -0
- package/lib/compiler/internal/build/BuildExecution.d.ts +4 -2
- package/lib/compiler/internal/build/BuildExecution.js +40 -12
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +5 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +9 -7
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/internal/javascriptRuntimeCapabilities.d.ts +13 -4
- package/lib/internal/javascriptRuntimeCapabilities.js +56 -6
- package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
- package/lib/internal/nativeBinary.d.ts +3 -3
- package/lib/internal/nativeBinary.js +3 -3
- package/lib/internal/pluginSource.d.ts +1 -0
- package/lib/internal/pluginSource.js +1 -0
- package/lib/internal/pluginSource.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +6 -1
- package/lib/internal/resolveNodeBinary.js +6 -2
- package/lib/internal/resolveNodeBinary.js.map +1 -1
- package/lib/internal/runtimeExecutableIdentity.d.ts +22 -13
- package/lib/internal/runtimeExecutableIdentity.js +192 -102
- package/lib/internal/runtimeExecutableIdentity.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +58 -4
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.d.ts +5 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js +7 -2
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js.map +1 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js +8 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js.map +1 -1
- package/lib/plugin/internal/CapabilityResolutionFormat.d.ts +21 -62
- package/lib/plugin/internal/CapabilityResolutionFormat.js +15 -106
- package/lib/plugin/internal/CapabilityResolutionFormat.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +6 -0
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +4 -4
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.d.ts +24 -14
- package/lib/plugin/internal/load/loadProjectPlugins.js +141 -56
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/readCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/readCapabilityResolution.js +8 -5
- package/lib/plugin/internal/readCapabilityResolution.js.map +1 -1
- package/lib/plugin/internal/source/GoEnvironmentReading.d.ts +48 -0
- package/lib/plugin/internal/source/GoEnvironmentReading.js +156 -0
- package/lib/plugin/internal/source/GoEnvironmentReading.js.map +1 -0
- package/lib/plugin/internal/source/NativeSourcePackages.d.ts +51 -13
- package/lib/plugin/internal/source/NativeSourcePackages.js +182 -27
- package/lib/plugin/internal/source/NativeSourcePackages.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +42 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +68 -7
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.d.ts +5 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.js +14 -8
- package/lib/plugin/internal/source/PluginBuildEnvironmentWitness.js.map +1 -1
- package/lib/plugin/internal/source/PluginContentIdentities.d.ts +265 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js +452 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js.map +1 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.d.ts +63 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js +128 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js.map +1 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.d.ts +10 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js +12 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
- package/lib/plugin/internal/source/SourcePluginWorkspace.d.ts +53 -19
- package/lib/plugin/internal/source/SourcePluginWorkspace.js +111 -22
- package/lib/plugin/internal/source/SourcePluginWorkspace.js.map +1 -1
- package/lib/plugin/internal/source/buildSourcePlugin.d.ts +34 -18
- package/lib/plugin/internal/source/buildSourcePlugin.js +52 -24
- package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/source/computeCacheKey.d.ts +25 -7
- package/lib/plugin/internal/source/computeCacheKey.js +85 -34
- package/lib/plugin/internal/source/computeCacheKey.js.map +1 -1
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.d.ts +7 -3
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js +75 -102
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironment.d.ts +8 -3
- package/lib/plugin/internal/source/pluginBuildEnvironment.js +8 -4
- package/lib/plugin/internal/source/pluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js +12 -2
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildVersions.d.ts +2 -2
- package/lib/plugin/internal/source/pluginBuildVersions.js +4 -17
- package/lib/plugin/internal/source/pluginBuildVersions.js.map +1 -1
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.d.ts +6 -5
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +10 -17
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceState.d.ts +6 -2
- package/lib/plugin/internal/source/pluginSourceState.js +20 -8
- package/lib/plugin/internal/source/pluginSourceState.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceStateHolds.d.ts +7 -2
- package/lib/plugin/internal/source/pluginSourceStateHolds.js +12 -7
- package/lib/plugin/internal/source/pluginSourceStateHolds.js.map +1 -1
- package/lib/plugin/internal/source/processPluginBuildEnvironment.d.ts +7 -2
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js +8 -3
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/provenPluginSourceDigest.d.ts +28 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js +41 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js.map +1 -0
- package/lib/plugin/internal/source/pruneCacheFileRoot.d.ts +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js.map +1 -1
- package/lib/plugin/internal/source/ttscPackageVersion.d.ts +26 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js +47 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js.map +1 -0
- package/lib/plugin/internal/writeCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/writeCapabilityResolution.js +11 -7
- package/lib/plugin/internal/writeCapabilityResolution.js.map +1 -1
- package/lib/plugin/resolveCapabilityPlugins.js +67 -15
- package/lib/plugin/resolveCapabilityPlugins.js.map +1 -1
- package/package.json +8 -8
- package/src/compiler/internal/build/BuildExecution.ts +46 -13
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +10 -2
- package/src/internal/javascriptRuntimeCapabilities.ts +71 -5
- package/src/internal/nativeBinary.ts +3 -3
- package/src/internal/pluginSource.ts +1 -0
- package/src/internal/resolveNodeBinary.ts +12 -1
- package/src/internal/runtimeExecutableIdentity.ts +227 -141
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +68 -3
- package/src/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.ts +11 -2
- package/src/launcher/internal/ttscserver/runTtscserver.ts +18 -1
- package/src/plugin/internal/CapabilityResolutionFormat.ts +23 -107
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +14 -4
- package/src/plugin/internal/load/loadProjectPlugins.ts +421 -211
- package/src/plugin/internal/readCapabilityResolution.ts +17 -6
- package/src/plugin/internal/source/GoEnvironmentReading.ts +178 -0
- package/src/plugin/internal/source/NativeSourcePackages.ts +365 -48
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +83 -5
- package/src/plugin/internal/source/PluginBuildEnvironmentWitness.ts +18 -8
- package/src/plugin/internal/source/PluginContentIdentities.ts +563 -0
- package/src/plugin/internal/source/PluginLoadAnswers.ts +151 -0
- package/src/plugin/internal/source/SourceBuildCacheLayout.ts +14 -0
- package/src/plugin/internal/source/SourcePluginWorkspace.ts +148 -25
- package/src/plugin/internal/source/buildSourcePlugin.ts +104 -36
- package/src/plugin/internal/source/computeCacheKey.ts +129 -55
- package/src/plugin/internal/source/hashPluginBuildEnvironment.ts +152 -105
- package/src/plugin/internal/source/pluginBuildEnvironment.ts +9 -2
- package/src/plugin/internal/source/pluginBuildEnvironmentWorker.ts +18 -2
- package/src/plugin/internal/source/pluginBuildVersions.ts +5 -26
- package/src/plugin/internal/source/pluginModuleReplaceDirectories.ts +13 -25
- package/src/plugin/internal/source/pluginSourceState.ts +28 -12
- package/src/plugin/internal/source/pluginSourceStateHolds.ts +15 -8
- package/src/plugin/internal/source/processPluginBuildEnvironment.ts +8 -2
- package/src/plugin/internal/source/provenPluginSourceDigest.ts +45 -0
- package/src/plugin/internal/source/pruneCacheFileRoot.ts +3 -2
- package/src/plugin/internal/source/ttscPackageVersion.ts +45 -0
- package/src/plugin/internal/writeCapabilityResolution.ts +29 -8
- package/src/plugin/resolveCapabilityPlugins.ts +87 -13
|
@@ -4,6 +4,7 @@ import { SHARE_ENV, Worker } from "node:worker_threads";
|
|
|
4
4
|
|
|
5
5
|
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
6
6
|
import { PluginBuildEnvironmentWitness } from "./PluginBuildEnvironmentWitness";
|
|
7
|
+
import { PluginContentIdentities } from "./PluginContentIdentities";
|
|
7
8
|
import { pluginBuildEnvironment } from "./pluginBuildEnvironment";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -74,25 +75,92 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
74
75
|
: undefined;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Qualify a batch in one synchronous observation transaction. Shared SDK
|
|
80
|
+
* paths and the complete variable identity are read once, even when several
|
|
81
|
+
* plugin directories use them. Missing readings remain explicitly missing.
|
|
82
|
+
*
|
|
83
|
+
* WARNING (#1712): this map belongs only to the following synchronous proof.
|
|
84
|
+
* Never retain it across an await, delivery, build boundary or publication. A
|
|
85
|
+
* process-permanent positive witness would miss changed Go tools and GOENV
|
|
86
|
+
* files (#1516); independently checking it in every helper instead multiplies
|
|
87
|
+
* a thousands-file GOROOT scan by modules and proof layers.
|
|
88
|
+
*
|
|
89
|
+
* @evidence contracts/common.md#principled-implementation One current variable snapshot and native path observation are compared against each reading's own expected witness; conflicting expected states cannot both pass.
|
|
90
|
+
* @evidence contracts/common.md#clear-and-simple-design One batch operation owns shared validation without changing synchronous reads or native worker publication boundaries.
|
|
91
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Undefined is retained for absent or stale authority; no positive verdict survives this explicit observation transaction.
|
|
92
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs state scope, missing semantics and the performance/correctness regressions prevented by the lifetime restriction.
|
|
93
|
+
* @evidence contracts/portability.md#os-neutral-implementation Existing native witness keys preserve filesystem, link and ambient-variable distinctions; no platform case assumption is added.
|
|
94
|
+
* @evidence contracts/performance.md#efficient-algorithms Full variables are indexed once; each distinct witnessed path is queried once while each reading compares its own witness entries. Work is proportional to variable bytes, total witness entries and unique native dependencies rather than repeated native SDK scans.
|
|
95
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Only current native observations within this synchronous batch are shared; the returned digests do not authorize reuse after another asynchronous boundary.
|
|
96
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources The native observation map is call-local and the digest map transfers to its immediate proof caller; no handle or historical registry is acquired.
|
|
97
|
+
*/
|
|
98
|
+
export function cachedAll(
|
|
99
|
+
directories: Iterable<string>,
|
|
100
|
+
): ReadonlyMap<string, string | undefined> {
|
|
101
|
+
let variables: string | undefined;
|
|
102
|
+
const current = new Map<string, string>();
|
|
103
|
+
const result = new Map<string, string | undefined>();
|
|
104
|
+
for (const directory of directories) {
|
|
105
|
+
if (result.has(directory)) continue;
|
|
106
|
+
const known = readings.get(
|
|
107
|
+
directory + (variables ??= key("", process.env)),
|
|
108
|
+
);
|
|
109
|
+
result.set(
|
|
110
|
+
directory,
|
|
111
|
+
known !== undefined &&
|
|
112
|
+
PluginBuildEnvironmentWitness.holds(known.witness, undefined, current)
|
|
113
|
+
? known.environment
|
|
114
|
+
: undefined,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
77
120
|
/**
|
|
78
121
|
* Read synchronously for clients whose API owns synchronous native work.
|
|
79
122
|
* Explicit refresh preserves the original fresh-comparison semantics.
|
|
80
123
|
*
|
|
124
|
+
* WARNING (#1725): the map above ends with the process, and every consumer
|
|
125
|
+
* that proves a plugin-source state starts a new one: a bundler worker, a
|
|
126
|
+
* capability host, the language server. Without the project's record store
|
|
127
|
+
* each of them walked and hashed the whole GOROOT (1.7 s for the bundled
|
|
128
|
+
* toolchain) on its first proof. A caller that names its project lets a miss
|
|
129
|
+
* prove the SDK and executables from the plugin cache's records.
|
|
130
|
+
*
|
|
131
|
+
* @param directory Plugin source directory whose build environment is read.
|
|
132
|
+
* @param refresh Bypass a cached reading.
|
|
133
|
+
* @param projectRoot Project whose plugin cache root holds the records.
|
|
81
134
|
* @evidence contracts/common.md#principled-implementation The same native reader constructs a digest paired with its pre-read witness; optional cached reuse validates current variables/metadata. A fresh synchronous reading is published without a separate post-read qualification here and relies on the native reader's premises.
|
|
82
135
|
* @evidence contracts/common.md#clear-and-simple-design The synchronous boundary shares cached authority and delegates fresh observation to its owning reader.
|
|
83
136
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts A requested refresh actually probes the selected native toolchain.
|
|
84
137
|
* @evidence contracts/common.md#meaningful-documentation Native prose identifies the synchronous execution owner and explicit refresh meaning.
|
|
85
138
|
* @evidence contracts/portability.md#os-neutral-implementation Native Go selection and filesystem witnesses remain delegated to the shared reader.
|
|
86
139
|
* @evidence contracts/performance.md#efficient-algorithms Hits pay complete variable-text indexing and native witness queries. Misses/refresh merge environment values, perform actual toolchain/SDK/content work, then rebuild the full variable-text key for publication; native/path/file/name/value bytes contribute cost beyond invocation count.
|
|
87
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Synchronous and asynchronous clients share the same qualified readings.
|
|
140
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Synchronous and asynchronous clients share the same qualified readings; a miss of a caller naming its project takes SDK and executable digests from the record store across processes.
|
|
88
141
|
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Retention belongs to the namespace; this call publishes one replacement record.
|
|
89
142
|
*/
|
|
90
|
-
export function read(
|
|
143
|
+
export function read(
|
|
144
|
+
directory: string,
|
|
145
|
+
refresh = false,
|
|
146
|
+
projectRoot?: string,
|
|
147
|
+
): string {
|
|
91
148
|
const known = refresh ? undefined : cached(directory);
|
|
92
149
|
if (known !== undefined) return known;
|
|
93
150
|
const env = SidecarEnvironment.merge(process.env);
|
|
94
151
|
const witness: PluginBuildEnvironmentWitness.Record = new Map();
|
|
95
|
-
const environment = pluginBuildEnvironment(
|
|
152
|
+
const environment = pluginBuildEnvironment(
|
|
153
|
+
directory,
|
|
154
|
+
env,
|
|
155
|
+
witness,
|
|
156
|
+
projectRoot === undefined
|
|
157
|
+
? undefined
|
|
158
|
+
: PluginContentIdentities.open({
|
|
159
|
+
projectRoot,
|
|
160
|
+
env,
|
|
161
|
+
sources: [directory],
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
96
164
|
readings.set(key(directory, env), { environment, witness });
|
|
97
165
|
return environment;
|
|
98
166
|
}
|
|
@@ -106,6 +174,14 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
106
174
|
* requests can create a worker after retirement. Refresh bypasses a cached
|
|
107
175
|
* reading but can still share an equivalent in-flight request.
|
|
108
176
|
*
|
|
177
|
+
* A caller that names its project lets the worker prove the SDK and
|
|
178
|
+
* executables from the plugin cache's records (#1722). The worker is its own
|
|
179
|
+
* isolate, so without them it reads the whole GOROOT once per process, which
|
|
180
|
+
* a bundler or runtime restarting on every edit pays every time.
|
|
181
|
+
*
|
|
182
|
+
* @param directory Plugin source directory whose build environment is read.
|
|
183
|
+
* @param refresh Bypass a cached reading.
|
|
184
|
+
* @param projectRoot Project whose plugin cache root holds the records.
|
|
109
185
|
* @evidence contracts/common.md#principled-implementation Worker results publish only under their exact current variable identity and still-current native pre-read witness; changed or unwitnessable transfer windows reject instead of publishing authority or retrying indefinitely.
|
|
110
186
|
* @evidence contracts/common.md#clear-and-simple-design Qualified hits return immediately; equivalent misses share one pending promise and exclusive queued worker request.
|
|
111
187
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Go/environment/SDK preparation occurs in the worker rather than blocking the async host or fabricating a digest from compiler output.
|
|
@@ -118,6 +194,7 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
118
194
|
export async function prepare(
|
|
119
195
|
directory: string,
|
|
120
196
|
refresh = false,
|
|
197
|
+
projectRoot?: string,
|
|
121
198
|
): Promise<string> {
|
|
122
199
|
const known = refresh ? undefined : cached(directory);
|
|
123
200
|
if (known !== undefined) return known;
|
|
@@ -126,7 +203,7 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
126
203
|
const existing = pending.get(identity);
|
|
127
204
|
if (existing !== undefined) return existing;
|
|
128
205
|
const request = (async () => {
|
|
129
|
-
const reading = await observe(directory, env);
|
|
206
|
+
const reading = await observe(directory, env, projectRoot);
|
|
130
207
|
if (
|
|
131
208
|
identity !== key(directory, process.env) ||
|
|
132
209
|
!PluginBuildEnvironmentWitness.holds(reading.witness)
|
|
@@ -158,6 +235,7 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
158
235
|
function observe(
|
|
159
236
|
directory: string,
|
|
160
237
|
env: NodeJS.ProcessEnv,
|
|
238
|
+
projectRoot: string | undefined,
|
|
161
239
|
): Promise<Reading> {
|
|
162
240
|
const request = queue.then(
|
|
163
241
|
() =>
|
|
@@ -198,7 +276,7 @@ export namespace PluginBuildEnvironmentReadings {
|
|
|
198
276
|
current.on("error", onError);
|
|
199
277
|
current.on("exit", onExit);
|
|
200
278
|
try {
|
|
201
|
-
current.postMessage({ directory, env });
|
|
279
|
+
current.postMessage({ directory, env, projectRoot });
|
|
202
280
|
} catch (error) {
|
|
203
281
|
release(false);
|
|
204
282
|
reject(error);
|
|
@@ -144,7 +144,9 @@ export namespace PluginBuildEnvironmentWitness {
|
|
|
144
144
|
* observation. The existing private opt-in trace retains the first actual
|
|
145
145
|
* mismatch without repeating its lookup or changing the refusal. An optional
|
|
146
146
|
* observation label separates preparation and build epochs in that trace; it
|
|
147
|
-
* does not change validation or authorize publication.
|
|
147
|
+
* does not change validation or authorize publication. A supplied native
|
|
148
|
+
* observation map belongs to one synchronous batch only; never reuse it after
|
|
149
|
+
* an await, delivery, environment mutation or publication boundary.
|
|
148
150
|
*
|
|
149
151
|
* @evidence contracts/common.md#principled-implementation Universal comparison requires every dependency to match its pre-read signature and immediately rejects a refused or changed path.
|
|
150
152
|
* @evidence contracts/common.md#clear-and-simple-design Validation uses the same signature helper as capture, keeping identity and timestamp policy in one place.
|
|
@@ -153,16 +155,24 @@ export namespace PluginBuildEnvironmentWitness {
|
|
|
153
155
|
* @evidence contracts/portability.md#os-neutral-implementation Validation reads actual Node metadata using the same link-following semantics as capture.
|
|
154
156
|
* @evidence contracts/performance.md#efficient-algorithms Validation iterates dependencies until mismatch and performs native stat/link queries or ambient-variable serialization. Windows environment matching enumerates names and lowercases text per witnessed variable, so P alone does not bound that work. Native path/link/name/value/numeric bytes contribute cost; file content is not read and unavailable native observations share the helper's missing marker. An enabled private trace serializes the first mismatch's already-computed text through its existing bounded sink.
|
|
155
157
|
*
|
|
156
|
-
* @
|
|
158
|
+
* @evidence contracts/performance.md#reuse-equivalent-work A caller-owned synchronous batch may share current native observations, comparing each witness against its own expected state; ordinary calls and all later observation phases establish new validity.
|
|
157
159
|
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Validation retains no handles or additional historical state.
|
|
158
160
|
*/
|
|
159
|
-
export function holds(
|
|
161
|
+
export function holds(
|
|
162
|
+
witness: Record,
|
|
163
|
+
observation?: string,
|
|
164
|
+
currentReadings?: Map<string, string>,
|
|
165
|
+
): boolean {
|
|
160
166
|
for (const [file, recorded] of witness) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
?
|
|
165
|
-
:
|
|
167
|
+
let current = currentReadings?.get(file);
|
|
168
|
+
if (current === undefined) {
|
|
169
|
+
current = file.startsWith(ENVIRONMENT_PREFIX)
|
|
170
|
+
? environmentSignature(file.slice(ENVIRONMENT_PREFIX.length))
|
|
171
|
+
: file.startsWith(LINK_PREFIX)
|
|
172
|
+
? linkSignature(file.slice(LINK_PREFIX.length))
|
|
173
|
+
: signature(file);
|
|
174
|
+
currentReadings?.set(file, current);
|
|
175
|
+
}
|
|
166
176
|
if (current !== recorded) {
|
|
167
177
|
E2ETrace.capabilityResolution(
|
|
168
178
|
"plugin-build-environment-witness-mismatch",
|