@telorun/kernel 0.85.0 → 0.86.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.
@@ -122,9 +122,27 @@ export declare class EvaluationContext implements IEvaluationContext {
122
122
  protected readonly declaredManifests: Map<string, ResourceManifest>;
123
123
  /** Per-resource dependency names, captured at create() time — BEFORE Phase-5
124
124
  * injection swaps refs for live instances, so the walk sees plain objects and
125
- * cannot wander into a controller's (possibly cyclic) object graph. Read only
126
- * when init fails, to attribute each failure to its cause. */
125
+ * cannot wander into a controller's (possibly cyclic) object graph.
126
+ *
127
+ * Read twice, and RETAINED for the context's lifetime because of the second
128
+ * reader: to attribute an init failure to its cause, and to order teardown
129
+ * (`teardownOrder`) so a consumer's inverses run while the resources it holds
130
+ * are still alive. */
127
131
  private readonly resourceDependencies;
132
+ /**
133
+ * Names resolved by NAME during initialization, rather than through a
134
+ * declared reference slot — so a resource somebody may be holding, with no
135
+ * edge recording who.
136
+ *
137
+ * The set is of TARGETS, not of pairs: the door that records
138
+ * (`ModuleContext.getInstance`) is reached as `ctx.moduleContext`, which every
139
+ * resource of the module shares, so there is no caller to attribute the read
140
+ * to. That is enough for the one decision that depends on it — see
141
+ * {@link impactedBy}.
142
+ */
143
+ protected readonly opaquelyRead: Set<string>;
144
+ /** Record a by-name resolution. Called by the recording door only. */
145
+ protected recordOpaqueRead(name: string): void;
128
146
  /**
129
147
  * Optional hook called between create() and init() for each resource.
130
148
  * Set by the kernel to inject live instances into reference fields.
@@ -231,6 +249,22 @@ export declare class EvaluationContext implements IEvaluationContext {
231
249
  */
232
250
  hasManifest(name: string): boolean;
233
251
  registerManifest(resource: ResourceManifest): void;
252
+ /**
253
+ * Forget a declaration entirely — the inverse of {@link registerManifest}.
254
+ *
255
+ * Reconciliation's other half: {@link unwindResources} disposes the INSTANCE,
256
+ * and this clears everything keyed by the name so the same name can be
257
+ * declared again. Without it `registerManifest` refuses with
258
+ * `ERR_DUPLICATE_RESOURCE`, which is the right answer for a manifest
259
+ * declaring one name twice and the wrong one for a second load of the same
260
+ * manifest.
261
+ *
262
+ * Every per-name record goes, not just the declaration: a resource left in
263
+ * `withheldResources` would be skipped by the init loop for the life of the
264
+ * kernel, and a stale `createdInstances` entry would have the loop initialize
265
+ * the object built from the PREVIOUS declaration.
266
+ */
267
+ deregisterManifest(name: string): void;
234
268
  /**
235
269
  * The manifest a name was DECLARED with, resolved scope-local first and then
236
270
  * up the enclosing chain — the order `getInstance` and the CEL `resources`
@@ -320,39 +354,138 @@ export declare class EvaluationContext implements IEvaluationContext {
320
354
  */
321
355
  createScopeHandle(manifests: ResourceManifest[]): ScopeHandle;
322
356
  /**
323
- * Cascade teardown depth-first through the tree:
324
- * 1. Tear down child contexts in reverse registration order.
325
- * 2. Tear down own resource instances in reverse registration order,
326
- * emitting a Teardown event for each via the injected emit callback.
357
+ * Cascade teardown through the tree:
358
+ * 1. Tear down own resource instances in {@link teardownOrder}, emitting a
359
+ * Teardown event for each via the injected emit callback.
360
+ * 2. Sweep any child context still standing, in {@link childTeardownOrder}.
361
+ *
362
+ * **Own resources go FIRST, and the child sweep is a backstop.** A child
363
+ * context that belongs to a resource is torn down by that resource's own
364
+ * inverse — an import's `init()` returns `child.teardownResources()`, and so
365
+ * does a template's — so it already unwinds at its owner's position in step 1,
366
+ * which is the position the edges put it at. Running a child cascade ahead of
367
+ * step 1 tore every imported library down before any resource of THIS context,
368
+ * so an app resource holding `!ref Alias.name` unwound after its provider was
369
+ * already gone, and the owner's inverse then found nothing left to do.
370
+ *
371
+ * Sweeping afterwards rather than not at all is what still reclaims a context
372
+ * no inverse claims: a `lifecycle: shared` library, which is spawned under the
373
+ * root and deliberately gives no importer a claim on it, and an import whose
374
+ * `init()` never ran to register one. `teardownResources` is idempotent, so a
375
+ * context already taken down in step 1 costs the sweep nothing.
327
376
  */
328
377
  teardownResources(): Promise<void>;
329
378
  /**
330
- * Child contexts in teardown order: ascending `teardownPriority` (default 0),
331
- * with the base reverse-registration order preserved within each tier.
379
+ * Unwind SOME of this context's resources and leave the rest running.
380
+ *
381
+ * The reconciliation half of teardown: a host that has decided which
382
+ * declarations moved unwinds exactly {@link impactedBy}'s answer, then
383
+ * re-registers and re-initializes. Ordering is {@link teardownOrder}
384
+ * restricted to the selection, so a consumer still unwinds before what it
385
+ * holds — and the selection being closed under holders is what makes that
386
+ * true of the resources left standing as well, since none of them holds
387
+ * anything in it.
388
+ *
389
+ * The context keeps its state: it is neither draining nor torn down, and no
390
+ * child context is swept, because a child belonging to an unwound import goes
391
+ * down with that import's own inverse exactly as it does at teardown.
392
+ *
393
+ * A name with no live instance is skipped rather than reported — a resource
394
+ * that failed to initialize has nothing to unwind, and a host asking for it is
395
+ * asking about a declaration, not about an instance.
396
+ */
397
+ unwindResources(names: ReadonlySet<string>): Promise<void>;
398
+ private raiseTeardownFailures;
399
+ /** Unwind the given entries in the order supplied, aggregating what refused.
400
+ * Failures are returned rather than thrown so one refusing inverse cannot
401
+ * strand the resources after it — the log sinks above all. */
402
+ private unwindEach;
403
+ /**
404
+ * Child contexts for the backstop sweep: ascending `teardownPriority`
405
+ * (default 0), reverse registration within a tier.
406
+ *
407
+ * What reaches the sweep is a context no resource's inverse claimed, which in
408
+ * practice is the `lifecycle: shared` libraries. Those are spawned under the
409
+ * ROOT and give no importer a claim, so nothing but this orders them — and
410
+ * reverse registration alone does not, since a singleton is registered when
411
+ * the FIRST import reaches it, which for an import declared inside another
412
+ * library is after that library's own context. `TEARDOWN_LAST` on the context
413
+ * is what keeps a singleton alive until the libraries borrowing it have gone.
332
414
  *
333
- * The same rule `teardownOrder` applies to resource instances, and for the
334
- * same reason: reverse registration is reverse init order in the happy path,
335
- * but a node that must reliably outlive the rest has to say so rather than
336
- * depend on when it happened to be created. A `lifecycle: shared` library is
337
- * registered when the FIRST import reaches it — which, for an import declared
338
- * inside another library, is after that library's own context — so reverse
339
- * registration would tear the singleton down while a borrower still holds it.
415
+ * Its protection now stops at library-against-library. Every resource of the
416
+ * context that owns the sweep has already unwound by the time it runs, which
417
+ * is the ordering the sweep used to invert.
340
418
  */
341
419
  private childTeardownOrder;
342
420
  /**
343
- * Resource instances in teardown order: ascending `teardownPriority`, with the
344
- * base reverse-insertion order preserved within each priority tier.
421
+ * Resource instances in teardown order: ascending `teardownPriority` as a hard
422
+ * tier, and within a tier a consumer before every resource it holds
423
+ * ({@link reverseTopologicalOrder} over the create-time edges), with reverse
424
+ * insertion as the tiebreak.
345
425
  *
346
- * The base order is reverse *insertion*, which is reverse init order in the
347
- * happy path but the init loop is a multi-pass retry, so a resource that
348
- * failed its first pass lands later in the map than its topological rank
349
- * implies. That makes the dependency graph an unreliable way to say "last".
350
- * A resource that must reliably outlive the rest declares it directly via
351
- * `teardownPriority` (log sinks set `TEARDOWN_LAST`), so the generic teardown
352
- * path orders by a declared number rather than sniffing any one subsystem's
353
- * instance shape.
426
+ * `teardownPriority` is a TIER rather than another edge because it is the
427
+ * author's statement about an edge nothing captured: a log sink is reached
428
+ * through `ctx.log` rather than through a ref slot, so no walk of the manifest
429
+ * can find the resources that will log on the way down. Letting topology
430
+ * reorder across tiers would let one discovered edge override a declaration
431
+ * made precisely because the edges are not all discoverable.
354
432
  */
355
433
  private teardownOrder;
434
+ /**
435
+ * Every resource of this context that becomes invalid when `names` do — the
436
+ * named resources plus everything that transitively holds one
437
+ * ({@link impactClosure} over the same create-time edges teardown reads).
438
+ *
439
+ * What a reconciliation unwinds. A cross-module reference projects onto the
440
+ * local `Telo.Import` (`localDependencyNames`), so a change inside an
441
+ * imported library reaches this context as its import being impacted, and the
442
+ * library goes down with that import's own inverse — which is why this
443
+ * answers for one context rather than walking the tree.
444
+ *
445
+ * **`opaque` is what the answer cannot cover.** A name resolved by NAME during
446
+ * initialization ({@link opaquelyRead}) may be held by a resource no edge
447
+ * names, so a closure reaching one is not an answer at all. Those names are
448
+ * reported rather than absorbed: expanding the set to "every resource here"
449
+ * would sweep in the module document, which is not a resource a caller can
450
+ * unwind and re-register, and would present a whole-context rebuild as a
451
+ * narrowing. The caller escalates, and can say which resource forced it.
452
+ */
453
+ impactedBy(names: Iterable<string>): {
454
+ impacted: Set<string>;
455
+ opaque: string[];
456
+ };
457
+ /** Whether this resource's `run()` has been dispatched. A rebuilt resource
458
+ * that had been started is one nothing will start again — boot targets run
459
+ * once — so a caller reconciling has to escalate rather than leave it
460
+ * constructed and idle. */
461
+ wasStarted(name: string): boolean;
462
+ /** Drop a resource's published reading. A context with no `resources` scope of
463
+ * its own has nothing to drop; `ModuleContext` overrides. */
464
+ clearPublishedReading(name: string): void;
465
+ /** The declaration registered under `name` in THIS context, without the
466
+ * walk up the enclosing chain a name lookup does. */
467
+ declaredManifestFor(name: string): ResourceManifest | undefined;
468
+ /** Replace a declaration in place, without queueing the resource for
469
+ * creation. For a survivor of a reconciliation: its declaration is
470
+ * content-identical by construction, but the object carries fresh loader
471
+ * stamps (`metadata.sourceLine` above all), and a diagnostic anchored on the
472
+ * stale one points at a pre-edit line. */
473
+ refreshManifest(name: string, resource: ResourceManifest): void;
474
+ /** Re-open an initialized context for another initialization pass.
475
+ *
476
+ * The transition is the context's own, not a field a caller assigns: while it
477
+ * is open, a reference to a resource that has not been rebuilt yet must
478
+ * produce the deferral the init loop retries on rather than a hard
479
+ * not-found, and leaving it open after a failed pass turns every later
480
+ * lookup into that deferral with no pass coming. */
481
+ reopenForInitialization(): void;
482
+ /** Close a pass opened by {@link reopenForInitialization} that did not reach
483
+ * the end of `initializeResources`. */
484
+ closeInitialization(): void;
485
+ /** Names a resource resolved by NAME while this context was initializing, so
486
+ * no edge records who is holding them. Read by {@link impactedBy}; exposed so
487
+ * a host can report why a reconciliation could not be narrowed. */
488
+ opaqueReads(): ReadonlySet<string>;
356
489
  transientChild(context: Record<string, any>): EvaluationContext;
357
490
  /**
358
491
  * Invoke a resource by kind and name within this context's resourceInstances.
@@ -1 +1 @@
1
- {"version":3,"file":"evaluation-context.d.ts","sourceRoot":"","sources":["../src/evaluation-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluation-context.d.ts","sourceRoot":"","sources":["../src/evaluation-context.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,9 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { formatSpanCounter } from "./logging/span-id.js";
3
3
  import { deriveContext, getRefIdentity, isCompiledValue, isInvokeError, isCancellationError, isSuspension, resourceKey, UNCANCELLABLE_CONTEXT, } from "@telorun/sdk";
4
4
  import { RuntimeError } from "@telorun/sdk";
5
- import { evalPathCovers } from "@telorun/analyzer";
5
+ import { celResourceReads, evalPathCovers } from "@telorun/analyzer";
6
6
  import { effectOwnerOf, executeReturnedChain } from "./effect-scope.js";
7
+ import { impactClosure, reverseTopologicalOrder } from "./resource-edges.js";
7
8
  import { REDACTED, redactSensitive, sensitivePathsOfInstance, } from "./instance-sensitive-paths.js";
8
9
  import { classifyInitFailures, isDeferral, renderInitFailureText, summarizeInitFailures, } from "./init-failure-diagnostics.js";
9
10
  import { acceptReportedStatus, buildPublishedProps, diagnoseObservedStateAccess, } from "./observed-state.js";
@@ -521,9 +522,29 @@ export class EvaluationContext {
521
522
  declaredManifests = new Map();
522
523
  /** Per-resource dependency names, captured at create() time — BEFORE Phase-5
523
524
  * injection swaps refs for live instances, so the walk sees plain objects and
524
- * cannot wander into a controller's (possibly cyclic) object graph. Read only
525
- * when init fails, to attribute each failure to its cause. */
525
+ * cannot wander into a controller's (possibly cyclic) object graph.
526
+ *
527
+ * Read twice, and RETAINED for the context's lifetime because of the second
528
+ * reader: to attribute an init failure to its cause, and to order teardown
529
+ * (`teardownOrder`) so a consumer's inverses run while the resources it holds
530
+ * are still alive. */
526
531
  resourceDependencies = new Map();
532
+ /**
533
+ * Names resolved by NAME during initialization, rather than through a
534
+ * declared reference slot — so a resource somebody may be holding, with no
535
+ * edge recording who.
536
+ *
537
+ * The set is of TARGETS, not of pairs: the door that records
538
+ * (`ModuleContext.getInstance`) is reached as `ctx.moduleContext`, which every
539
+ * resource of the module shares, so there is no caller to attribute the read
540
+ * to. That is enough for the one decision that depends on it — see
541
+ * {@link impactedBy}.
542
+ */
543
+ opaquelyRead = new Set();
544
+ /** Record a by-name resolution. Called by the recording door only. */
545
+ recordOpaqueRead(name) {
546
+ this.opaquelyRead.add(name);
547
+ }
527
548
  /**
528
549
  * Optional hook called between create() and init() for each resource.
529
550
  * Set by the kernel to inject live instances into reference fields.
@@ -730,6 +751,32 @@ export class EvaluationContext {
730
751
  this.pendingResources.push(resource);
731
752
  this.declaredManifests.set(name, resource);
732
753
  }
754
+ /**
755
+ * Forget a declaration entirely — the inverse of {@link registerManifest}.
756
+ *
757
+ * Reconciliation's other half: {@link unwindResources} disposes the INSTANCE,
758
+ * and this clears everything keyed by the name so the same name can be
759
+ * declared again. Without it `registerManifest` refuses with
760
+ * `ERR_DUPLICATE_RESOURCE`, which is the right answer for a manifest
761
+ * declaring one name twice and the wrong one for a second load of the same
762
+ * manifest.
763
+ *
764
+ * Every per-name record goes, not just the declaration: a resource left in
765
+ * `withheldResources` would be skipped by the init loop for the life of the
766
+ * kernel, and a stale `createdInstances` entry would have the loop initialize
767
+ * the object built from the PREVIOUS declaration.
768
+ */
769
+ deregisterManifest(name) {
770
+ this.declaredManifests.delete(name);
771
+ this.resourceDependencies.delete(name);
772
+ this.createdInstances.delete(name);
773
+ this.withheldResources.delete(name);
774
+ this.recreatedResources.delete(name);
775
+ this.opaquelyRead.delete(name);
776
+ const pending = this.pendingResources.findIndex((r) => r.metadata?.name === name);
777
+ if (pending >= 0)
778
+ this.pendingResources.splice(pending, 1);
779
+ }
733
780
  /**
734
781
  * The manifest a name was DECLARED with, resolved scope-local first and then
735
782
  * up the enclosing chain — the order `getInstance` and the CEL `resources`
@@ -890,7 +937,12 @@ export class EvaluationContext {
890
937
  progress = true;
891
938
  const createdRes = created.resource;
892
939
  const refs = collectResourceRefs(createdRes);
893
- this.resourceDependencies.set(name, localDependencyNames(refs));
940
+ // `resource` rather than `createdRes`: the registered declaration
941
+ // still holds its expressions, while the created copy holds the
942
+ // values they were expanded to.
943
+ this.resourceDependencies.set(name, [
944
+ ...new Set([...localDependencyNames(refs), ...celResourceReads(resource)]),
945
+ ]);
894
946
  const payload = {
895
947
  resource: {
896
948
  kind: createdRes.kind,
@@ -1001,9 +1053,6 @@ export class EvaluationContext {
1001
1053
  await this.publishSnapshot(name);
1002
1054
  this.resourceInstances.set(name, { resource, instance });
1003
1055
  this.createdInstances.delete(name);
1004
- // Read only on failure, and this one succeeded — drop it rather than
1005
- // holding a dep-name array per resource for the context's lifetime.
1006
- this.resourceDependencies.delete(name);
1007
1056
  errors.delete(name);
1008
1057
  progress = true;
1009
1058
  await this.emit(`${resource.kind}.${resource.metadata.name}.Initialized`, {
@@ -1173,15 +1222,32 @@ export class EvaluationContext {
1173
1222
  };
1174
1223
  }
1175
1224
  /**
1176
- * Cascade teardown depth-first through the tree:
1177
- * 1. Tear down child contexts in reverse registration order.
1178
- * 2. Tear down own resource instances in reverse registration order,
1179
- * emitting a Teardown event for each via the injected emit callback.
1225
+ * Cascade teardown through the tree:
1226
+ * 1. Tear down own resource instances in {@link teardownOrder}, emitting a
1227
+ * Teardown event for each via the injected emit callback.
1228
+ * 2. Sweep any child context still standing, in {@link childTeardownOrder}.
1229
+ *
1230
+ * **Own resources go FIRST, and the child sweep is a backstop.** A child
1231
+ * context that belongs to a resource is torn down by that resource's own
1232
+ * inverse — an import's `init()` returns `child.teardownResources()`, and so
1233
+ * does a template's — so it already unwinds at its owner's position in step 1,
1234
+ * which is the position the edges put it at. Running a child cascade ahead of
1235
+ * step 1 tore every imported library down before any resource of THIS context,
1236
+ * so an app resource holding `!ref Alias.name` unwound after its provider was
1237
+ * already gone, and the owner's inverse then found nothing left to do.
1238
+ *
1239
+ * Sweeping afterwards rather than not at all is what still reclaims a context
1240
+ * no inverse claims: a `lifecycle: shared` library, which is spawned under the
1241
+ * root and deliberately gives no importer a claim on it, and an import whose
1242
+ * `init()` never ran to register one. `teardownResources` is idempotent, so a
1243
+ * context already taken down in step 1 costs the sweep nothing.
1180
1244
  */
1181
1245
  // eslint-disable-next-line @typescript-eslint/member-ordering
1182
1246
  async teardownResources() {
1183
1247
  this.state = "Draining";
1184
- const failures = [];
1248
+ const failures = await this.unwindEach(this.teardownOrder());
1249
+ // The backstop: whatever no resource's inverse claimed. Everything an import
1250
+ // or a template owns is already down, so this is a no-op for it.
1185
1251
  for (const child of this.childTeardownOrder()) {
1186
1252
  try {
1187
1253
  await child.teardownResources();
@@ -1190,7 +1256,48 @@ export class EvaluationContext {
1190
1256
  failures.push({ resource: "(child context)", error: err });
1191
1257
  }
1192
1258
  }
1193
- for (const [key, { resource, instance }] of this.teardownOrder()) {
1259
+ this.state = "Teardown";
1260
+ this.raiseTeardownFailures(failures);
1261
+ }
1262
+ /**
1263
+ * Unwind SOME of this context's resources and leave the rest running.
1264
+ *
1265
+ * The reconciliation half of teardown: a host that has decided which
1266
+ * declarations moved unwinds exactly {@link impactedBy}'s answer, then
1267
+ * re-registers and re-initializes. Ordering is {@link teardownOrder}
1268
+ * restricted to the selection, so a consumer still unwinds before what it
1269
+ * holds — and the selection being closed under holders is what makes that
1270
+ * true of the resources left standing as well, since none of them holds
1271
+ * anything in it.
1272
+ *
1273
+ * The context keeps its state: it is neither draining nor torn down, and no
1274
+ * child context is swept, because a child belonging to an unwound import goes
1275
+ * down with that import's own inverse exactly as it does at teardown.
1276
+ *
1277
+ * A name with no live instance is skipped rather than reported — a resource
1278
+ * that failed to initialize has nothing to unwind, and a host asking for it is
1279
+ * asking about a declaration, not about an instance.
1280
+ */
1281
+ // eslint-disable-next-line @typescript-eslint/member-ordering
1282
+ async unwindResources(names) {
1283
+ const selected = this.teardownOrder().filter(([, entry]) => names.has(entry.resource.metadata.name));
1284
+ this.raiseTeardownFailures(await this.unwindEach(selected));
1285
+ }
1286
+ raiseTeardownFailures(failures) {
1287
+ if (failures.length === 0)
1288
+ return;
1289
+ throw new RuntimeError("ERR_TEARDOWN_FAILED", `${failures.length} resource(s) failed during teardown`, failures.map(({ resource, error }) => ({
1290
+ severity: "error",
1291
+ message: error instanceof Error ? error.message : String(error),
1292
+ resource,
1293
+ })));
1294
+ }
1295
+ /** Unwind the given entries in the order supplied, aggregating what refused.
1296
+ * Failures are returned rather than thrown so one refusing inverse cannot
1297
+ * strand the resources after it — the log sinks above all. */
1298
+ async unwindEach(entries) {
1299
+ const failures = [];
1300
+ for (const [key, { resource, instance }] of entries) {
1194
1301
  const label = `${resource.kind}.${resource.metadata.name}`;
1195
1302
  // A reading belongs to the run that produced it. The WeakMap would drop it
1196
1303
  // with the instance anyway; clearing here also covers an instance something
@@ -1242,27 +1349,27 @@ export class EvaluationContext {
1242
1349
  failures.push({ resource: `${label} (Teardown event)`, error: err });
1243
1350
  }
1244
1351
  this.resourceInstances.delete(key);
1352
+ // A torn-down resource must stop being readable: a CEL expansion that still
1353
+ // found its reading would bake a value nothing is serving any more.
1354
+ this.clearPublishedReading(resource.metadata.name);
1245
1355
  }
1246
- this.state = "Teardown";
1247
- if (failures.length > 0) {
1248
- throw new RuntimeError("ERR_TEARDOWN_FAILED", `${failures.length} resource(s) failed during teardown`, failures.map(({ resource, error }) => ({
1249
- severity: "error",
1250
- message: error instanceof Error ? error.message : String(error),
1251
- resource,
1252
- })));
1253
- }
1356
+ return failures;
1254
1357
  }
1255
1358
  /**
1256
- * Child contexts in teardown order: ascending `teardownPriority` (default 0),
1257
- * with the base reverse-registration order preserved within each tier.
1359
+ * Child contexts for the backstop sweep: ascending `teardownPriority`
1360
+ * (default 0), reverse registration within a tier.
1361
+ *
1362
+ * What reaches the sweep is a context no resource's inverse claimed, which in
1363
+ * practice is the `lifecycle: shared` libraries. Those are spawned under the
1364
+ * ROOT and give no importer a claim, so nothing but this orders them — and
1365
+ * reverse registration alone does not, since a singleton is registered when
1366
+ * the FIRST import reaches it, which for an import declared inside another
1367
+ * library is after that library's own context. `TEARDOWN_LAST` on the context
1368
+ * is what keeps a singleton alive until the libraries borrowing it have gone.
1258
1369
  *
1259
- * The same rule `teardownOrder` applies to resource instances, and for the
1260
- * same reason: reverse registration is reverse init order in the happy path,
1261
- * but a node that must reliably outlive the rest has to say so rather than
1262
- * depend on when it happened to be created. A `lifecycle: shared` library is
1263
- * registered when the FIRST import reaches it — which, for an import declared
1264
- * inside another library, is after that library's own context — so reverse
1265
- * registration would tear the singleton down while a borrower still holds it.
1370
+ * Its protection now stops at library-against-library. Every resource of the
1371
+ * context that owns the sweep has already unwound by the time it runs, which
1372
+ * is the ordering the sweep used to invert.
1266
1373
  */
1267
1374
  childTeardownOrder() {
1268
1375
  return [...this.children]
@@ -1271,17 +1378,17 @@ export class EvaluationContext {
1271
1378
  (b.teardownPriority ?? 0));
1272
1379
  }
1273
1380
  /**
1274
- * Resource instances in teardown order: ascending `teardownPriority`, with the
1275
- * base reverse-insertion order preserved within each priority tier.
1381
+ * Resource instances in teardown order: ascending `teardownPriority` as a hard
1382
+ * tier, and within a tier a consumer before every resource it holds
1383
+ * ({@link reverseTopologicalOrder} over the create-time edges), with reverse
1384
+ * insertion as the tiebreak.
1276
1385
  *
1277
- * The base order is reverse *insertion*, which is reverse init order in the
1278
- * happy path but the init loop is a multi-pass retry, so a resource that
1279
- * failed its first pass lands later in the map than its topological rank
1280
- * implies. That makes the dependency graph an unreliable way to say "last".
1281
- * A resource that must reliably outlive the rest declares it directly via
1282
- * `teardownPriority` (log sinks set `TEARDOWN_LAST`), so the generic teardown
1283
- * path orders by a declared number rather than sniffing any one subsystem's
1284
- * instance shape.
1386
+ * `teardownPriority` is a TIER rather than another edge because it is the
1387
+ * author's statement about an edge nothing captured: a log sink is reached
1388
+ * through `ctx.log` rather than through a ref slot, so no walk of the manifest
1389
+ * can find the resources that will log on the way down. Letting topology
1390
+ * reorder across tiers would let one discovered edge override a declaration
1391
+ * made precisely because the edges are not all discoverable.
1285
1392
  */
1286
1393
  teardownOrder() {
1287
1394
  // A borrowed instance is torn down by the scope that declared it, never
@@ -1289,10 +1396,93 @@ export class EvaluationContext {
1289
1396
  const entries = [...this.resourceInstances.entries()]
1290
1397
  .filter(([name]) => !this.borrowedResources.has(name))
1291
1398
  .reverse();
1292
- // Stable sort by priority (default 0); Array.prototype.sort is stable, so
1293
- // the reverse-insertion order survives within each tier.
1294
- return entries.sort(([, a], [, b]) => (a.instance?.teardownPriority ?? 0) -
1295
- (b.instance?.teardownPriority ?? 0));
1399
+ const tiers = new Map();
1400
+ for (const entry of entries) {
1401
+ const priority = entry[1].instance?.teardownPriority ?? 0;
1402
+ const tier = tiers.get(priority);
1403
+ if (tier)
1404
+ tier.push(entry);
1405
+ else
1406
+ tiers.set(priority, [entry]);
1407
+ }
1408
+ return [...tiers.keys()]
1409
+ .sort((a, b) => a - b)
1410
+ .flatMap((priority) => reverseTopologicalOrder(tiers.get(priority), (value) => value.resource.metadata.name, (name) => this.resourceDependencies.get(name)));
1411
+ }
1412
+ /**
1413
+ * Every resource of this context that becomes invalid when `names` do — the
1414
+ * named resources plus everything that transitively holds one
1415
+ * ({@link impactClosure} over the same create-time edges teardown reads).
1416
+ *
1417
+ * What a reconciliation unwinds. A cross-module reference projects onto the
1418
+ * local `Telo.Import` (`localDependencyNames`), so a change inside an
1419
+ * imported library reaches this context as its import being impacted, and the
1420
+ * library goes down with that import's own inverse — which is why this
1421
+ * answers for one context rather than walking the tree.
1422
+ *
1423
+ * **`opaque` is what the answer cannot cover.** A name resolved by NAME during
1424
+ * initialization ({@link opaquelyRead}) may be held by a resource no edge
1425
+ * names, so a closure reaching one is not an answer at all. Those names are
1426
+ * reported rather than absorbed: expanding the set to "every resource here"
1427
+ * would sweep in the module document, which is not a resource a caller can
1428
+ * unwind and re-register, and would present a whole-context rebuild as a
1429
+ * narrowing. The caller escalates, and can say which resource forced it.
1430
+ */
1431
+ // eslint-disable-next-line @typescript-eslint/member-ordering
1432
+ impactedBy(names) {
1433
+ const impacted = impactClosure(names, this.resourceDependencies);
1434
+ const opaque = [...impacted].filter((name) => this.opaquelyRead.has(name));
1435
+ return { impacted, opaque };
1436
+ }
1437
+ /** Whether this resource's `run()` has been dispatched. A rebuilt resource
1438
+ * that had been started is one nothing will start again — boot targets run
1439
+ * once — so a caller reconciling has to escalate rather than leave it
1440
+ * constructed and idle. */
1441
+ wasStarted(name) {
1442
+ const instance = this.resourceInstances.get(name)?.instance;
1443
+ return instance !== undefined && startedInstances.has(instance);
1444
+ }
1445
+ /** Drop a resource's published reading. A context with no `resources` scope of
1446
+ * its own has nothing to drop; `ModuleContext` overrides. */
1447
+ clearPublishedReading(name) {
1448
+ void name;
1449
+ }
1450
+ /** The declaration registered under `name` in THIS context, without the
1451
+ * walk up the enclosing chain a name lookup does. */
1452
+ declaredManifestFor(name) {
1453
+ return this.declaredManifests.get(name);
1454
+ }
1455
+ /** Replace a declaration in place, without queueing the resource for
1456
+ * creation. For a survivor of a reconciliation: its declaration is
1457
+ * content-identical by construction, but the object carries fresh loader
1458
+ * stamps (`metadata.sourceLine` above all), and a diagnostic anchored on the
1459
+ * stale one points at a pre-edit line. */
1460
+ refreshManifest(name, resource) {
1461
+ if (this.declaredManifests.has(name))
1462
+ this.declaredManifests.set(name, resource);
1463
+ }
1464
+ /** Re-open an initialized context for another initialization pass.
1465
+ *
1466
+ * The transition is the context's own, not a field a caller assigns: while it
1467
+ * is open, a reference to a resource that has not been rebuilt yet must
1468
+ * produce the deferral the init loop retries on rather than a hard
1469
+ * not-found, and leaving it open after a failed pass turns every later
1470
+ * lookup into that deferral with no pass coming. */
1471
+ reopenForInitialization() {
1472
+ if (this.state === "Initialized")
1473
+ this.state = "Validated";
1474
+ }
1475
+ /** Close a pass opened by {@link reopenForInitialization} that did not reach
1476
+ * the end of `initializeResources`. */
1477
+ closeInitialization() {
1478
+ if (this.state === "Validated")
1479
+ this.state = "Initialized";
1480
+ }
1481
+ /** Names a resource resolved by NAME while this context was initializing, so
1482
+ * no edge records who is holding them. Read by {@link impactedBy}; exposed so
1483
+ * a host can report why a reconciliation could not be narrowed. */
1484
+ opaqueReads() {
1485
+ return this.opaquelyRead;
1296
1486
  }
1297
1487
  transientChild(context) {
1298
1488
  return new EvaluationContext(this.source, { ...this.context, ...context }, this._createInstance, this._secretValues, this.emit);