@telora/daemon 0.22.13 → 0.22.52

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 (155) hide show
  1. package/build-info.json +5 -3
  2. package/dist/backends/index.d.ts.map +1 -1
  3. package/dist/backends/index.js +1 -0
  4. package/dist/backends/index.js.map +1 -1
  5. package/dist/ci/ci-status.d.ts.map +1 -1
  6. package/dist/ci/ci-status.js +1 -0
  7. package/dist/ci/ci-status.js.map +1 -1
  8. package/dist/completion/detector.d.ts +9 -0
  9. package/dist/completion/detector.d.ts.map +1 -1
  10. package/dist/completion/detector.js +18 -0
  11. package/dist/completion/detector.js.map +1 -1
  12. package/dist/completion/event-phases.d.ts +20 -0
  13. package/dist/completion/event-phases.d.ts.map +1 -1
  14. package/dist/completion/event-phases.js +46 -13
  15. package/dist/completion/event-phases.js.map +1 -1
  16. package/dist/completion/event.d.ts +69 -9
  17. package/dist/completion/event.d.ts.map +1 -1
  18. package/dist/completion/event.js +109 -22
  19. package/dist/completion/event.js.map +1 -1
  20. package/dist/completion/liveness-firing.d.ts +27 -0
  21. package/dist/completion/liveness-firing.d.ts.map +1 -0
  22. package/dist/completion/liveness-firing.js +79 -0
  23. package/dist/completion/liveness-firing.js.map +1 -0
  24. package/dist/completion/review-exit-phase.js +4 -4
  25. package/dist/completion/review-exit-phase.js.map +1 -1
  26. package/dist/completion/state-cascade.d.ts.map +1 -1
  27. package/dist/completion/state-cascade.js +8 -0
  28. package/dist/completion/state-cascade.js.map +1 -1
  29. package/dist/completion/stdin-turn-tracker.d.ts +19 -0
  30. package/dist/completion/stdin-turn-tracker.d.ts.map +1 -0
  31. package/dist/completion/stdin-turn-tracker.js +57 -0
  32. package/dist/completion/stdin-turn-tracker.js.map +1 -0
  33. package/dist/completion/supervision-firing-record.d.ts +242 -0
  34. package/dist/completion/supervision-firing-record.d.ts.map +1 -0
  35. package/dist/completion/supervision-firing-record.js +292 -0
  36. package/dist/completion/supervision-firing-record.js.map +1 -0
  37. package/dist/completion/team-lifecycle.d.ts.map +1 -1
  38. package/dist/completion/team-lifecycle.js +9 -0
  39. package/dist/completion/team-lifecycle.js.map +1 -1
  40. package/dist/directive/directive-dispatch.d.ts +7 -1
  41. package/dist/directive/directive-dispatch.d.ts.map +1 -1
  42. package/dist/directive/directive-dispatch.js +105 -39
  43. package/dist/directive/directive-dispatch.js.map +1 -1
  44. package/dist/directive/directive-executor.d.ts +1 -10
  45. package/dist/directive/directive-executor.d.ts.map +1 -1
  46. package/dist/directive/directive-executor.js +51 -33
  47. package/dist/directive/directive-executor.js.map +1 -1
  48. package/dist/directive/directive-queue.d.ts +35 -9
  49. package/dist/directive/directive-queue.d.ts.map +1 -1
  50. package/dist/directive/directive-queue.js +15 -8
  51. package/dist/directive/directive-queue.js.map +1 -1
  52. package/dist/directive/directive-verify-hold-gate.d.ts +33 -0
  53. package/dist/directive/directive-verify-hold-gate.d.ts.map +1 -0
  54. package/dist/directive/directive-verify-hold-gate.js +57 -0
  55. package/dist/directive/directive-verify-hold-gate.js.map +1 -0
  56. package/dist/directive/phase-sync.d.ts +11 -0
  57. package/dist/directive/phase-sync.d.ts.map +1 -1
  58. package/dist/directive/phase-sync.js +12 -0
  59. package/dist/directive/phase-sync.js.map +1 -1
  60. package/dist/drift/staleness-sensor.d.ts +62 -67
  61. package/dist/drift/staleness-sensor.d.ts.map +1 -1
  62. package/dist/drift/staleness-sensor.js +233 -68
  63. package/dist/drift/staleness-sensor.js.map +1 -1
  64. package/dist/drift/staleness.d.ts +8 -0
  65. package/dist/drift/staleness.d.ts.map +1 -1
  66. package/dist/drift/staleness.js +7 -1
  67. package/dist/drift/staleness.js.map +1 -1
  68. package/dist/focus/focus-engine.js +1 -1
  69. package/dist/focus/focus-engine.js.map +1 -1
  70. package/dist/focus/focus-team-state.d.ts.map +1 -1
  71. package/dist/focus/focus-team-state.js +2 -0
  72. package/dist/focus/focus-team-state.js.map +1 -1
  73. package/dist/focus/focus-worktree-state.d.ts.map +1 -1
  74. package/dist/focus/focus-worktree-state.js +5 -2
  75. package/dist/focus/focus-worktree-state.js.map +1 -1
  76. package/dist/focus/listener-spawn.d.ts +39 -0
  77. package/dist/focus/listener-spawn.d.ts.map +1 -1
  78. package/dist/focus/listener-spawn.js +140 -24
  79. package/dist/focus/listener-spawn.js.map +1 -1
  80. package/dist/focus/listener.d.ts.map +1 -1
  81. package/dist/focus/listener.js +53 -25
  82. package/dist/focus/listener.js.map +1 -1
  83. package/dist/focus/session-health.d.ts +25 -3
  84. package/dist/focus/session-health.d.ts.map +1 -1
  85. package/dist/focus/session-health.js +32 -1
  86. package/dist/focus/session-health.js.map +1 -1
  87. package/dist/focus/team-actionable-work.d.ts +41 -2
  88. package/dist/focus/team-actionable-work.d.ts.map +1 -1
  89. package/dist/focus/team-actionable-work.js +52 -7
  90. package/dist/focus/team-actionable-work.js.map +1 -1
  91. package/dist/merge/focus-merge.d.ts +12 -1
  92. package/dist/merge/focus-merge.d.ts.map +1 -1
  93. package/dist/merge/focus-merge.js +33 -2
  94. package/dist/merge/focus-merge.js.map +1 -1
  95. package/dist/nexus/return.d.ts +105 -1
  96. package/dist/nexus/return.d.ts.map +1 -1
  97. package/dist/nexus/return.js +237 -47
  98. package/dist/nexus/return.js.map +1 -1
  99. package/dist/queries/schemas.d.ts +12 -0
  100. package/dist/queries/schemas.d.ts.map +1 -1
  101. package/dist/queries/schemas.js +7 -0
  102. package/dist/queries/schemas.js.map +1 -1
  103. package/dist/queries/sessions.d.ts.map +1 -1
  104. package/dist/queries/sessions.js +1 -0
  105. package/dist/queries/sessions.js.map +1 -1
  106. package/dist/shell/heartbeat-metadata.d.ts +102 -0
  107. package/dist/shell/heartbeat-metadata.d.ts.map +1 -0
  108. package/dist/shell/heartbeat-metadata.js +172 -0
  109. package/dist/shell/heartbeat-metadata.js.map +1 -0
  110. package/dist/shell/heartbeat.d.ts +7 -22
  111. package/dist/shell/heartbeat.d.ts.map +1 -1
  112. package/dist/shell/heartbeat.js +120 -89
  113. package/dist/shell/heartbeat.js.map +1 -1
  114. package/dist/shell/unified-shell.d.ts.map +1 -1
  115. package/dist/shell/unified-shell.js +21 -12
  116. package/dist/shell/unified-shell.js.map +1 -1
  117. package/dist/spawn/helpers.d.ts.map +1 -1
  118. package/dist/spawn/helpers.js +7 -1
  119. package/dist/spawn/helpers.js.map +1 -1
  120. package/dist/spawn/process-spawn.d.ts +32 -1
  121. package/dist/spawn/process-spawn.d.ts.map +1 -1
  122. package/dist/spawn/process-spawn.js +43 -5
  123. package/dist/spawn/process-spawn.js.map +1 -1
  124. package/dist/testing/fixtures/index.js +1 -1
  125. package/dist/types/index.js +1 -1
  126. package/dist/types/session.d.ts +11 -0
  127. package/dist/types/session.d.ts.map +1 -1
  128. package/dist/update/auto-update-idle.d.ts +22 -0
  129. package/dist/update/auto-update-idle.d.ts.map +1 -1
  130. package/dist/update/auto-update-idle.js +8 -1
  131. package/dist/update/auto-update-idle.js.map +1 -1
  132. package/dist/update/auto-update.d.ts +0 -6
  133. package/dist/update/auto-update.d.ts.map +1 -1
  134. package/dist/update/auto-update.js +20 -6
  135. package/dist/update/auto-update.js.map +1 -1
  136. package/dist/update/version-check.d.ts +73 -0
  137. package/dist/update/version-check.d.ts.map +1 -1
  138. package/dist/update/version-check.js +107 -11
  139. package/dist/update/version-check.js.map +1 -1
  140. package/dist/verify/stall-detector-config.d.ts +26 -0
  141. package/dist/verify/stall-detector-config.d.ts.map +1 -1
  142. package/dist/verify/stall-detector-config.js +32 -0
  143. package/dist/verify/stall-detector-config.js.map +1 -1
  144. package/dist/verify/stall-detectors.d.ts +40 -0
  145. package/dist/verify/stall-detectors.d.ts.map +1 -1
  146. package/dist/verify/stall-detectors.js +60 -6
  147. package/dist/verify/stall-detectors.js.map +1 -1
  148. package/dist/verify/stalled-team-backstop.d.ts +43 -0
  149. package/dist/verify/stalled-team-backstop.d.ts.map +1 -0
  150. package/dist/verify/stalled-team-backstop.js +131 -0
  151. package/dist/verify/stalled-team-backstop.js.map +1 -0
  152. package/dist/worktree/verify-interlock.d.ts.map +1 -1
  153. package/dist/worktree/verify-interlock.js +3 -1
  154. package/dist/worktree/verify-interlock.js.map +1 -1
  155. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import type { StageDirective } from '../types/index.js';
1
+ import type { CompactRecipe, StageDirective } from '../types/index.js';
2
2
  import type { SessionContinuity } from '../session/session-lineage.js';
3
3
  /**
4
4
  * Pending spawn directive content, keyed by focusId.
@@ -33,6 +33,15 @@ export interface PendingSpawnDirective {
33
33
  engine?: string | null;
34
34
  localModel?: string | null;
35
35
  sessionType: 'coding' | 'review';
36
+ /**
37
+ * The stage directive's compaction recipe, carried onto the spawn so a
38
+ * spawn-coinciding /compact runs at the kickoff->coding boundary (UDE #9): the
39
+ * spawn path composes it as the FIRST stdin turn, ahead of the kickoff message,
40
+ * so on a resume it sheds the prior (scoping) context BEFORE the first coding
41
+ * cycle rather than after it. Null when the directive declares no compact. Was
42
+ * previously dropped (logged undelivered) on the no-active-team path.
43
+ */
44
+ compact?: CompactRecipe | null;
36
45
  /** Session-id map slot this spawn reads/writes (INJ-B). */
37
46
  lineage: string;
38
47
  /** Resume-vs-fresh policy for this spawn's lineage (INJ-B). */
@@ -44,6 +53,16 @@ export interface PendingSpawnDirective {
44
53
  * can detect divergent content within the 60s skip window.
45
54
  */
46
55
  contentHash: string;
56
+ /**
57
+ * The workflow stage this directive belongs to (the focus's
58
+ * current_workflow_stage_id when the directive was stashed), or null when the
59
+ * stash site did not know it. Read at consumption to DROP a directive whose
60
+ * stage the focus has already left -- the 2026-09-06 focus 6f866509 case, where
61
+ * a directive queued for the verifying stage was consumed by a spawn 0.4s after
62
+ * the focus moved to reviewing. Optional for back-compat with entries built
63
+ * before the field existed (a null origin skips the currency check).
64
+ */
65
+ originStageId?: string | null;
47
66
  /**
48
67
  * Blocked-on-capacity backoff counter. Incremented each poll tick that a
49
68
  * re-fire is suppressed because an equivalent directive is already queued
@@ -75,15 +94,22 @@ export declare function computeDirectiveHash(directive: StageDirective): string;
75
94
  * the directive that produced it. */
76
95
  export declare const SPAWN_GUARD_WINDOW_MS = 60000;
77
96
  /**
78
- * Decide whether executeSpawnDirective should skip the terminate+respawn
79
- * cycle for a recently-spawned team. Pure function so the divergence rule
80
- * is unit-testable without mocking the active teams map.
97
+ * Decide what executeSpawnDirective should do with a live team when a stage
98
+ * directive fires. Pure function so the whole terminate rule is unit-testable
99
+ * without mocking the active teams map or terminateTeam.
81
100
  *
82
101
  * - skip: team is within the spawn window AND its last-consumed directive
83
- * hash matches the new directive's hash. The team is already running
84
- * under the same intent.
85
- * - respawn: team is older than the window OR the hashes diverge. Both
86
- * cases require terminate+respawn so the team picks up fresh intent.
102
+ * hash matches the new directive's hash. Already running the same intent.
103
+ * - defer_young_divergence: team is within the spawn window but the hashes
104
+ * diverge. Directive dispatch does NOT own team lifecycle -- a young team is
105
+ * NOT terminated because a newer stage's directive content differs; it is
106
+ * left to finish its turn, and the divergent directive (already stashed in
107
+ * pendingSpawnDirectives) rides its natural exit. This is the 2026-09-06
108
+ * focus 6f866509 fix: a 28s-old team must not be killed 0.4s after a stage
109
+ * change.
110
+ * - respawn: team is OLDER than the window. Only here does executeSpawnDirective
111
+ * terminate + respawn, and only because the team has had its full turn -- NOT
112
+ * because content diverged.
87
113
  */
88
114
  export declare function shouldSkipSpawnDirective(args: {
89
115
  team: {
@@ -92,7 +118,7 @@ export declare function shouldSkipSpawnDirective(args: {
92
118
  } | undefined;
93
119
  contentHash: string;
94
120
  now: number;
95
- }): 'skip' | 'respawn';
121
+ }): 'skip' | 'defer_young_divergence' | 'respawn';
96
122
  /**
97
123
  * Consume a pending spawn directive for a focus.
98
124
  * Returns the directive content and removes it from the map.
@@ -1 +1 @@
1
- {"version":3,"file":"directive-queue.d.ts","sourceRoot":"","sources":["../../src/directive/directive-queue.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIvE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;;OAMG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACjC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;OAWG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,oCAA2C,CAAC;AAE/E;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CAMtE;AAED;sCACsC;AACtC,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,IAAI,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,CAAC;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,GAAG,SAAS,CAMrB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAM/F;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,qBAAqB,GAC/B,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAE3F;AAED,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAElD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAEV;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACrD,cAAc,EAAE,OAAO,CAAC;IACxB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAGV;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAKV;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM/D"}
1
+ {"version":3,"file":"directive-queue.d.ts","sourceRoot":"","sources":["../../src/directive/directive-queue.ts"],"names":[],"mappings":"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"}
@@ -36,15 +36,22 @@ export function computeDirectiveHash(directive) {
36
36
  * the directive that produced it. */
37
37
  export const SPAWN_GUARD_WINDOW_MS = 60000;
38
38
  /**
39
- * Decide whether executeSpawnDirective should skip the terminate+respawn
40
- * cycle for a recently-spawned team. Pure function so the divergence rule
41
- * is unit-testable without mocking the active teams map.
39
+ * Decide what executeSpawnDirective should do with a live team when a stage
40
+ * directive fires. Pure function so the whole terminate rule is unit-testable
41
+ * without mocking the active teams map or terminateTeam.
42
42
  *
43
43
  * - skip: team is within the spawn window AND its last-consumed directive
44
- * hash matches the new directive's hash. The team is already running
45
- * under the same intent.
46
- * - respawn: team is older than the window OR the hashes diverge. Both
47
- * cases require terminate+respawn so the team picks up fresh intent.
44
+ * hash matches the new directive's hash. Already running the same intent.
45
+ * - defer_young_divergence: team is within the spawn window but the hashes
46
+ * diverge. Directive dispatch does NOT own team lifecycle -- a young team is
47
+ * NOT terminated because a newer stage's directive content differs; it is
48
+ * left to finish its turn, and the divergent directive (already stashed in
49
+ * pendingSpawnDirectives) rides its natural exit. This is the 2026-09-06
50
+ * focus 6f866509 fix: a 28s-old team must not be killed 0.4s after a stage
51
+ * change.
52
+ * - respawn: team is OLDER than the window. Only here does executeSpawnDirective
53
+ * terminate + respawn, and only because the team has had its full turn -- NOT
54
+ * because content diverged.
48
55
  */
49
56
  export function shouldSkipSpawnDirective(args) {
50
57
  const { team, contentHash, now } = args;
@@ -53,7 +60,7 @@ export function shouldSkipSpawnDirective(args) {
53
60
  const age = now - team.startedAt.getTime();
54
61
  if (age >= SPAWN_GUARD_WINDOW_MS)
55
62
  return 'respawn';
56
- return team.lastConsumedDirectiveHash === contentHash ? 'skip' : 'respawn';
63
+ return team.lastConsumedDirectiveHash === contentHash ? 'skip' : 'defer_young_divergence';
57
64
  }
58
65
  /**
59
66
  * Consume a pending spawn directive for a focus.
@@ -1 +1 @@
1
- {"version":3,"file":"directive-queue.js","sourceRoot":"","sources":["../../src/directive/directive-queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"directive-queue.js","sourceRoot":"","sources":["../../src/directive/directive-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /** Injectable seam so callers unit-test the gate without a live verify. */
2
+ export interface DirectiveVerifyHoldDeps {
3
+ focusUnderVerifyHold?: (focusId: string) => boolean;
4
+ /**
5
+ * The session lineage of the directive being dispatched. A review-lineage
6
+ * directive is NEVER blocked by a verify hold: a review is exactly the work
7
+ * that must proceed while deliveries sit in verify -- it is what RELEASES them.
8
+ * This matches the already-declared downstream rule that review is always
9
+ * spawnable (resolveDirectiveExecutionMode defaults review -> spawn). Absent /
10
+ * any non-review value: the shared held-vs-unheld verdict decides as before.
11
+ */
12
+ lineage?: string;
13
+ }
14
+ /**
15
+ * True when a stage directive that would SPAWN (or respawn) a team for this
16
+ * focus must be suppressed because the focus has no team-actionable work: its
17
+ * worktree is held by an in-flight verify. Reads the one canonical predicate
18
+ * (focus/team-actionable-work.ts) shared with the spawn gate and the team-exit
19
+ * classifier.
20
+ *
21
+ * `hasUnheldActionableWork` is true by construction at this call site -- the
22
+ * directive executor only reaches a spawn-producing path for a focus it already
23
+ * decided has a directive to run; the hold is the only thing that can flip the
24
+ * shared verdict to "no actionable work". An inject to an already-live team is
25
+ * NOT a spawn and is never gated here; callers apply this only on their
26
+ * spawn-producing branches.
27
+ *
28
+ * The one exception is LINEAGE: a review-lineage directive is never blocked (see
29
+ * DirectiveVerifyHoldDeps.lineage) -- the review is the work that clears the very
30
+ * hold, so gating it on the hold would deadlock the focus in verify.
31
+ */
32
+ export declare function directiveSpawnBlockedByVerifyHold(focusId: string, deps?: DirectiveVerifyHoldDeps): boolean;
33
+ //# sourceMappingURL=directive-verify-hold-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directive-verify-hold-gate.d.ts","sourceRoot":"","sources":["../../src/directive/directive-verify-hold-gate.ts"],"names":[],"mappings":"AAgCA,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACpD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,uBAA4B,GACjC,OAAO,CAUT"}
@@ -0,0 +1,57 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/directive/directive-verify-hold-gate.test.ts,
3
+ // packages/daemon/src/directive/review-during-hold-terminates-coding.test.ts,
4
+ // packages/daemon/src/focus/team-actionable-work.test.ts
5
+ // PINNED-BY-END
6
+ /**
7
+ * Directive executor's read of the ONE actionable-work world-model.
8
+ *
9
+ * The directive dispatcher has two spawn-PRODUCING paths: the no-active-team
10
+ * fallback in executeInjectDirective (which stashes a PendingSpawnDirective for
11
+ * the listener to spawn) and executeSpawnDirective (which terminates the live
12
+ * team and stashes a respawn). Both would drive a team into a focus whose
13
+ * worktree is currently held by an in-flight verify -- a focus with NO
14
+ * team-actionable work -- which is exactly the respawn class that produced the
15
+ * 2026-09-06 storm (a lead spawned, ran one turn, found nothing it could commit
16
+ * or advance, and exited, 80 times).
17
+ *
18
+ * This module gives the directive executor the SAME verdict the spawn gate
19
+ * (focus/listener-spawn.ts) and the team-exit classifier read: the one predicate
20
+ * in focus/team-actionable-work.ts, with the verify-interlock hold as an input.
21
+ * So all four controllers cannot disagree about whether a focus has actionable
22
+ * work -- the "one world-model" this focus converges.
23
+ *
24
+ * @module directive/directive-verify-hold-gate
25
+ */
26
+ import { focusHasTeamActionableWork, focusUnderVerifyHold, } from '../focus/team-actionable-work.js';
27
+ /**
28
+ * True when a stage directive that would SPAWN (or respawn) a team for this
29
+ * focus must be suppressed because the focus has no team-actionable work: its
30
+ * worktree is held by an in-flight verify. Reads the one canonical predicate
31
+ * (focus/team-actionable-work.ts) shared with the spawn gate and the team-exit
32
+ * classifier.
33
+ *
34
+ * `hasUnheldActionableWork` is true by construction at this call site -- the
35
+ * directive executor only reaches a spawn-producing path for a focus it already
36
+ * decided has a directive to run; the hold is the only thing that can flip the
37
+ * shared verdict to "no actionable work". An inject to an already-live team is
38
+ * NOT a spawn and is never gated here; callers apply this only on their
39
+ * spawn-producing branches.
40
+ *
41
+ * The one exception is LINEAGE: a review-lineage directive is never blocked (see
42
+ * DirectiveVerifyHoldDeps.lineage) -- the review is the work that clears the very
43
+ * hold, so gating it on the hold would deadlock the focus in verify.
44
+ */
45
+ export function directiveSpawnBlockedByVerifyHold(focusId, deps = {}) {
46
+ // Review is always spawnable, hold or not -- it releases the deliveries the
47
+ // hold is holding. Read the lineage before the hold so a review directive is
48
+ // never suppressed.
49
+ if (deps.lineage === 'review')
50
+ return false;
51
+ const underVerifyHold = (deps.focusUnderVerifyHold ?? focusUnderVerifyHold)(focusId);
52
+ return !focusHasTeamActionableWork({
53
+ hasUnheldActionableWork: true,
54
+ underVerifyHold,
55
+ });
56
+ }
57
+ //# sourceMappingURL=directive-verify-hold-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directive-verify-hold-gate.js","sourceRoot":"","sources":["../../src/directive/directive-verify-hold-gate.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,+EAA+E;AAC/E,gFAAgF;AAChF,2DAA2D;AAC3D,gBAAgB;AAEhB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,kCAAkC,CAAC;AAgB1C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iCAAiC,CAC/C,OAAe,EACf,OAAgC,EAAE;IAElC,4EAA4E;IAC5E,6EAA6E;IAC7E,oBAAoB;IACpB,IAAI,IAAI,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,eAAe,GAAG,CAAC,IAAI,CAAC,oBAAoB,IAAI,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC;IACrF,OAAO,CAAC,0BAA0B,CAAC;QACjC,uBAAuB,EAAE,IAAI;QAC7B,eAAe;KAChB,CAAC,CAAC;AACL,CAAC"}
@@ -61,12 +61,23 @@ export declare function resolveFocusStageName(input: {
61
61
  * active-team guard suppresses the re-fire, and a successful review auto-approves
62
62
  * and leaves the stage -- so the re-fire is bounded, not a per-poll spin.
63
63
  *
64
+ * An OPERATOR-STOPPED focus is never stranded: it is stopped. Re-firing into a
65
+ * stop produced a three-controller livelock (2026-09-07) -- auto-review re-set
66
+ * review_requested_at because deliveries sat in verify, this predicate re-fired
67
+ * and stored a 35KB directive, and listener-spawn dropped it as held by an
68
+ * operator stop, every 30s without bound. The pending-directive spin-guard could
69
+ * not damp it: the listener's drop is what empties the queue that guard reads.
70
+ * The stop is read HERE, at the re-fire, because a directive stored while
71
+ * stopped is exactly what the stop exists to prevent -- retaining it downstream
72
+ * would defeat the stop rather than end the loop.
73
+ *
64
74
  * Pure and exported for unit testing.
65
75
  */
66
76
  export declare function shouldRefireStrandedReview(input: {
67
77
  stageName: string | undefined;
68
78
  reviewRequestedAt: string | null;
69
79
  hasActiveTeam: boolean;
80
+ operatorStopped?: boolean;
70
81
  }): boolean;
71
82
  /**
72
83
  * Synchronize `product_focuses.current_workflow_stage_id` with the focus's
@@ -1 +1 @@
1
- {"version":3,"file":"phase-sync.d.ts","sourceRoot":"","sources":["../../src/directive/phase-sync.ts"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAyCf;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,UAAU,EAAE,KAAK,CAAC;QAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,GAAG,MAAM,CAMT;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAKV;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCzB"}
1
+ {"version":3,"file":"phase-sync.d.ts","sourceRoot":"","sources":["../../src/directive/phase-sync.ts"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAyCf;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,UAAU,EAAE,KAAK,CAAC;QAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,GAAG,MAAM,CAMT;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAMV;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCzB"}
@@ -120,6 +120,16 @@ const REVIEW_STAGE_NAMES = new Set(['reviewing', 'review']);
120
120
  * active-team guard suppresses the re-fire, and a successful review auto-approves
121
121
  * and leaves the stage -- so the re-fire is bounded, not a per-poll spin.
122
122
  *
123
+ * An OPERATOR-STOPPED focus is never stranded: it is stopped. Re-firing into a
124
+ * stop produced a three-controller livelock (2026-09-07) -- auto-review re-set
125
+ * review_requested_at because deliveries sat in verify, this predicate re-fired
126
+ * and stored a 35KB directive, and listener-spawn dropped it as held by an
127
+ * operator stop, every 30s without bound. The pending-directive spin-guard could
128
+ * not damp it: the listener's drop is what empties the queue that guard reads.
129
+ * The stop is read HERE, at the re-fire, because a directive stored while
130
+ * stopped is exactly what the stop exists to prevent -- retaining it downstream
131
+ * would defeat the stop rather than end the loop.
132
+ *
123
133
  * Pure and exported for unit testing.
124
134
  */
125
135
  export function shouldRefireStrandedReview(input) {
@@ -129,6 +139,8 @@ export function shouldRefireStrandedReview(input) {
129
139
  return false;
130
140
  if (input.hasActiveTeam)
131
141
  return false;
142
+ if (input.operatorStopped)
143
+ return false;
132
144
  return true;
133
145
  }
134
146
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"phase-sync.js","sourceRoot":"","sources":["../../src/directive/phase-sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"phase-sync.js","sourceRoot":"","sources":["../../src/directive/phase-sync.ts"],"names":[],"mappings":"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"}
@@ -1,55 +1,5 @@
1
- /**
2
- * Propagation-staleness sensor (focus: "Propagation Staleness Is Invisible").
3
- *
4
- * The differential instrument this focus is named for: it computes
5
- * newest-available MINUS actually-running for a tracked target. Its first (and
6
- * directly observable) target is the running daemon vs the Gitea npm registry:
7
- *
8
- * running = ~/.telora/daemon.meta.json .version (this daemon's own build)
9
- * newest = the warm version cache .latestVersion (Gitea registry dist-tags.latest,
10
- * kept fresh by startVersionCacheRefreshLoop)
11
- *
12
- * CLOSING the gap, not reporting it. The daemon-version gap is machine-closable:
13
- * the safe-seam auto-update controller (auto-update.ts) already installs a newer
14
- * registry version at the next batch-safe idle seam. So when the gap is beyond
15
- * threshold this sensor DEFERS to that closer -- it does NOT tell a human "the
16
- * daemon is stale, restart it". Telling a human about a gap the machine is
17
- * already closing converts machine signal into human chore, and firing on a
18
- * healthy daemon that is merely deferring to its next safe seam is exactly the
19
- * failure mode this focus exists to remove.
20
- *
21
- * A human is involved ONLY where the machine genuinely cannot act: auto-update
22
- * is disabled for this daemon (installMode=npx, or --no-auto-update /
23
- * TELORA_AUTO_UPDATE=0, reflected as autoUpdateEnabled=false in daemon.meta.json).
24
- * The operator opted out of automation, so the machine cannot close the gap --
25
- * and even then the deliverable is a READY ACTION handed over (the exact
26
- * `npm install -g` command + restart), never an inbox item that merely says a
27
- * gap exists. That handover auto-resolves once the running version catches up,
28
- * and is retired immediately if auto-update is re-enabled (the machine reclaims
29
- * closure).
30
- *
31
- * Every tick leaves a trace (delegated-to-auto-update / handed-over /
32
- * back-in-sync / "measured, within threshold" / "UNMEASURED"), so an ABSENT
33
- * trace positively means "measured and in sync" -- never "not measured". Wedged
34
- * auto-update (enabled but not running) is made visible by the SEPARATE
35
- * auto-update decision heartbeat (auto-update.ts): an absent [auto-update] trace
36
- * identifies a controller that is not running. That is not re-derived here.
37
- *
38
- * Pure decision (computeDaemonVersionDifferential / decideStalenessAction) +
39
- * injected IO, mirroring ci-sensor-loop.ts, so the loop is unit-testable without
40
- * a live registry or DB. Registered in LOOP_REGISTRY under the opt-out guard
41
- * TELORA_STALENESS_SENSOR_LOOP.
42
- *
43
- * The two infra-owned targets observed 2026-07-24 (npmjs mirror serving a stale
44
- * version; Opus 5 seed merged-but-maybe-not-applied) are NOT computable from
45
- * this repo (no prod DB access; infra alone publishes to npmjs). They are
46
- * recorded, with their operator-facing close action, in
47
- * docs/runbook-propagation-staleness-targets.md -- the sensor deliberately does
48
- * NOT attempt those infra actions.
49
- *
50
- * @module staleness-sensor
51
- */
52
1
  import type { DaemonConfig } from '../types/index.js';
2
+ import { type VersionDistance } from '../update/version-check.js';
53
3
  /**
54
4
  * escalation_kind for a stale daemon that the machine CANNOT auto-close (auto-update
55
5
  * disabled). Carries a ready action, not a bare "gap exists" notice.
@@ -64,12 +14,7 @@ export declare const DAEMON_VERSION_TARGET = "daemon-version";
64
14
  * failure (0.20.21 vs 0.20.28 = 7 patches) is well past this floor.
65
15
  */
66
16
  export declare const DEFAULT_STALENESS_PATCH_THRESHOLD = 3;
67
- /** Component-wise magnitude of how far `running` is behind `newest` (clamped at 0). */
68
- export interface VersionDistance {
69
- major: number;
70
- minor: number;
71
- patch: number;
72
- }
17
+ export type { VersionDistance };
73
18
  /** The computed newest-vs-running differential for a tracked target. */
74
19
  export interface StalenessDifferential {
75
20
  target: string;
@@ -92,8 +37,11 @@ export declare function computeDaemonVersionDifferential(running: string | null,
92
37
  * What the sensor should do with the current differential.
93
38
  * - `delegate` -- gap is beyond threshold and the machine closes it itself
94
39
  * (auto-update enabled): defer to that closer, no human.
95
- * - `hand-over` -- gap is beyond threshold but the machine cannot act
96
- * (auto-update disabled): hand a human a ready action.
40
+ * - `hand-over` -- gap is beyond threshold and a human signal is owed: either
41
+ * the machine cannot act (auto-update disabled -> a ready
42
+ * action), OR the machine SHOULD act but the gap has persisted
43
+ * past the wedge window without the running version advancing
44
+ * (auto-update wedged -> a needs_operator signal).
97
45
  * - `resolve` -- an open handover exists but the machine is now closing the
98
46
  * gap (back within threshold, OR auto-update re-enabled).
99
47
  * - `none` -- nothing to do.
@@ -101,12 +49,30 @@ export declare function computeDaemonVersionDifferential(running: string | null,
101
49
  export type StalenessAction = 'delegate' | 'hand-over' | 'resolve' | 'none';
102
50
  /**
103
51
  * Pure decision. The pivot is `canMachineClose`: when the auto-update controller
104
- * owns closing the daemon-version gap, the sensor NEVER hands a human a report --
105
- * it defers (and retires any stale handover). A human is handed a ready action
106
- * ONLY when the machine genuinely cannot act. A null differential (unmeasurable)
107
- * never acts -- it is handled as a trace by the tick.
52
+ * owns closing the daemon-version gap, the sensor normally DEFERS and never hands
53
+ * a human a report (and retires any stale handover). Two things pull a human in:
54
+ * the machine genuinely cannot act (`!canMachineClose`), OR the machine can act
55
+ * but the SAME beyond-threshold gap has persisted past the wedge window without
56
+ * the running version advancing (`wedged`) -- a closer that is enabled but not
57
+ * applying is a failed close, a legitimate operator signal, not an in-flight one
58
+ * to stay silent about. A null differential (unmeasurable) never acts.
108
59
  */
109
- export declare function decideStalenessAction(diff: StalenessDifferential | null, hasOpen: boolean, canMachineClose: boolean): StalenessAction;
60
+ export declare function decideStalenessAction(diff: StalenessDifferential | null, hasOpen: boolean, canMachineClose: boolean, wedged?: boolean): StalenessAction;
61
+ /**
62
+ * Record that `causeKey` is currently a beyond-threshold, machine-closable gap
63
+ * and report whether it has persisted at/past `thresholdMs`. Prunes any other
64
+ * key so the store stays single-entry (a new cause_key -- running advanced or a
65
+ * new newest -- starts a fresh clock). Pure over the injected store, so a unit
66
+ * test drives it with a fresh Map and a fixed clock.
67
+ */
68
+ export declare function recordAndCheckGapWedged(store: Map<string, number>, causeKey: string, nowMs: number, thresholdMs: number): boolean;
69
+ /**
70
+ * Default wedge window in hours: how long a machine-closable, beyond-threshold
71
+ * gap may persist without the running version advancing before the closer is
72
+ * treated as wedged. Kept ABOVE the auto-update drain threshold (6h default) so a
73
+ * legitimately-busy daemon that will drain-and-update on its own is never flagged.
74
+ */
75
+ export declare const DEFAULT_STALENESS_WEDGE_THRESHOLD_HOURS = 12;
110
76
  /** Minimal open-escalation row shape the sensor's dedup / resolve reads. */
111
77
  interface StalenessEscalationRow {
112
78
  id: string;
@@ -126,10 +92,24 @@ export declare function isStalenessRefileSuppressed(rows: readonly StalenessEsca
126
92
  running: string;
127
93
  newest: string;
128
94
  }): boolean;
95
+ /**
96
+ * Why a human is owed a signal for a beyond-threshold gap:
97
+ * - `auto_update_disabled` -- the machine cannot act; hand a READY ACTION.
98
+ * - `auto_update_wedged` -- the machine SHOULD act but the gap has persisted
99
+ * past the wedge window without the running version
100
+ * advancing; the closer is enabled but not applying.
101
+ */
102
+ export type StalenessHandoverReason = 'auto_update_disabled' | 'auto_update_wedged';
129
103
  /** Injected IO for the sensor tick. Defaults reach for the real implementations. */
130
104
  export interface StalenessSensorDeps {
131
105
  readRunningVersion: () => string | null;
132
106
  readNewestAvailable: () => string | null;
107
+ /** The registry the `newest` reading was consulted from (warm cache), or null
108
+ * (legacy cache with no registry) -- used to ATTRIBUTE the reading. */
109
+ readReadingRegistry: () => string | null;
110
+ /** The registry npm resolves for an install of @telora/daemon -- the reading
111
+ * must attribute to THIS for its agreement to count. */
112
+ readInstallRegistry: () => string;
133
113
  patchThreshold: number;
134
114
  /**
135
115
  * True when the auto-update controller can close the daemon-version gap itself.
@@ -141,14 +121,28 @@ export interface StalenessSensorDeps {
141
121
  running: string;
142
122
  newest: string;
143
123
  }) => Promise<boolean>;
144
- /** Hand a human a READY ACTION when (and only when) the machine cannot act. */
124
+ /**
125
+ * Hand a human a signal for a beyond-threshold gap: a READY ACTION when the
126
+ * machine cannot act (reason auto_update_disabled), or a WEDGED-CLOSER signal
127
+ * when auto-update is enabled but not applying (reason auto_update_wedged).
128
+ */
145
129
  handOverReadyAction: (params: {
146
130
  organizationId: string;
147
131
  productId: string;
148
132
  diff: StalenessDifferential;
149
133
  readyCommand: string;
134
+ reason: StalenessHandoverReason;
135
+ registry: string;
150
136
  }) => Promise<void>;
151
137
  resolveStalenessEscalations: () => Promise<number>;
138
+ /**
139
+ * Whether a machine-closable, beyond-threshold gap for `causeKey` has persisted
140
+ * past the wedge window (auto-update enabled but the running version not
141
+ * advancing). Records first-seen on the way, so persistence is a code/state
142
+ * fact -- a test drives it with a stub returning true/false.
143
+ */
144
+ checkGapWedged: (causeKey: string, nowMs: number) => boolean;
145
+ now: () => number;
152
146
  }
153
147
  export interface StalenessSensorTickCounts {
154
148
  /** True when the differential could be computed (both versions known). */
@@ -157,8 +151,10 @@ export interface StalenessSensorTickCounts {
157
151
  behind: boolean;
158
152
  /** True when the machine (auto-update) owns closing the measured gap this tick. */
159
153
  delegatedToAutoUpdate: boolean;
160
- /** Ready-action handovers filed -- only when the machine genuinely cannot act. */
154
+ /** Handovers filed this tick (auto-update disabled OR wedged). */
161
155
  handoversToOperator: number;
156
+ /** Of the handovers, those filed because auto-update is enabled but WEDGED. */
157
+ wedgedSignalsFiled: number;
162
158
  escalationsResolved: number;
163
159
  }
164
160
  /**
@@ -172,5 +168,4 @@ export interface StalenessSensorTickCounts {
172
168
  * Every path emits a trace so an absent signal means "measured and in sync".
173
169
  */
174
170
  export declare function runStalenessSensorTick(config: DaemonConfig, deps?: StalenessSensorDeps): Promise<StalenessSensorTickCounts>;
175
- export {};
176
171
  //# sourceMappingURL=staleness-sensor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"staleness-sensor.d.ts","sourceRoot":"","sources":["../../src/drift/staleness-sensor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staleness-sensor.d.ts","sourceRoot":"","sources":["../../src/drift/staleness-sensor.ts"],"names":[],"mappings":"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"}