@telora/daemon 0.20.21 → 0.20.32

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 (115) hide show
  1. package/build-info.json +4 -3
  2. package/dist/audit-phase.d.ts +43 -6
  3. package/dist/audit-phase.d.ts.map +1 -1
  4. package/dist/audit-phase.js +124 -23
  5. package/dist/audit-phase.js.map +1 -1
  6. package/dist/auto-update.d.ts +87 -0
  7. package/dist/auto-update.d.ts.map +1 -1
  8. package/dist/auto-update.js +142 -8
  9. package/dist/auto-update.js.map +1 -1
  10. package/dist/cascade-restatement.d.ts +13 -147
  11. package/dist/cascade-restatement.d.ts.map +1 -1
  12. package/dist/cascade-restatement.js +13 -429
  13. package/dist/cascade-restatement.js.map +1 -1
  14. package/dist/focus-engine.d.ts.map +1 -1
  15. package/dist/focus-engine.js +15 -0
  16. package/dist/focus-engine.js.map +1 -1
  17. package/dist/focus-loop-registry.d.ts.map +1 -1
  18. package/dist/focus-loop-registry.js +43 -90
  19. package/dist/focus-loop-registry.js.map +1 -1
  20. package/dist/focus-loop.d.ts +0 -2
  21. package/dist/focus-loop.d.ts.map +1 -1
  22. package/dist/focus-loop.js +33 -25
  23. package/dist/focus-loop.js.map +1 -1
  24. package/dist/focus-phase.d.ts +26 -0
  25. package/dist/focus-phase.d.ts.map +1 -1
  26. package/dist/focus-phase.js +38 -0
  27. package/dist/focus-phase.js.map +1 -1
  28. package/dist/focus-prompt-builder.d.ts.map +1 -1
  29. package/dist/focus-prompt-builder.js +5 -1
  30. package/dist/focus-prompt-builder.js.map +1 -1
  31. package/dist/listener.d.ts.map +1 -1
  32. package/dist/listener.js +40 -9
  33. package/dist/listener.js.map +1 -1
  34. package/dist/loops/llm-client.d.ts.map +1 -1
  35. package/dist/loops/llm-client.js +17 -4
  36. package/dist/loops/llm-client.js.map +1 -1
  37. package/dist/prompt-listing.d.ts +25 -0
  38. package/dist/prompt-listing.d.ts.map +1 -1
  39. package/dist/prompt-listing.js +61 -0
  40. package/dist/prompt-listing.js.map +1 -1
  41. package/dist/queries/audit-runs.d.ts +56 -2
  42. package/dist/queries/audit-runs.d.ts.map +1 -1
  43. package/dist/queries/audit-runs.js +40 -0
  44. package/dist/queries/audit-runs.js.map +1 -1
  45. package/dist/queries/deliveries.d.ts +27 -0
  46. package/dist/queries/deliveries.d.ts.map +1 -1
  47. package/dist/queries/deliveries.js.map +1 -1
  48. package/dist/queries/focuses.d.ts +0 -9
  49. package/dist/queries/focuses.d.ts.map +1 -1
  50. package/dist/queries/focuses.js +0 -14
  51. package/dist/queries/focuses.js.map +1 -1
  52. package/dist/resolvers/index.d.ts +1 -1
  53. package/dist/resolvers/index.d.ts.map +1 -1
  54. package/dist/resolvers/index.js +1 -1
  55. package/dist/resolvers/index.js.map +1 -1
  56. package/dist/resolvers/shared/audit.d.ts +5 -0
  57. package/dist/resolvers/shared/audit.d.ts.map +1 -1
  58. package/dist/resolvers/shared/audit.js +8 -3
  59. package/dist/resolvers/shared/audit.js.map +1 -1
  60. package/dist/resolvers/shared/git-diff.d.ts +13 -0
  61. package/dist/resolvers/shared/git-diff.d.ts.map +1 -1
  62. package/dist/resolvers/shared/git-diff.js +30 -0
  63. package/dist/resolvers/shared/git-diff.js.map +1 -1
  64. package/dist/security-scan-engine.d.ts +9 -1
  65. package/dist/security-scan-engine.d.ts.map +1 -1
  66. package/dist/security-scan-engine.js +25 -2
  67. package/dist/security-scan-engine.js.map +1 -1
  68. package/dist/spawn/review-role-fallback.d.ts +74 -0
  69. package/dist/spawn/review-role-fallback.d.ts.map +1 -0
  70. package/dist/spawn/review-role-fallback.js +62 -0
  71. package/dist/spawn/review-role-fallback.js.map +1 -0
  72. package/dist/staleness-sensor.d.ts +153 -0
  73. package/dist/staleness-sensor.d.ts.map +1 -0
  74. package/dist/staleness-sensor.js +308 -0
  75. package/dist/staleness-sensor.js.map +1 -0
  76. package/dist/unified-shell.d.ts.map +1 -1
  77. package/dist/unified-shell.js +11 -0
  78. package/dist/unified-shell.js.map +1 -1
  79. package/dist/verification-engine.d.ts +17 -1
  80. package/dist/verification-engine.d.ts.map +1 -1
  81. package/dist/verification-engine.js +143 -104
  82. package/dist/verification-engine.js.map +1 -1
  83. package/dist/verification-feedback.d.ts +68 -1
  84. package/dist/verification-feedback.d.ts.map +1 -1
  85. package/dist/verification-feedback.js +175 -0
  86. package/dist/verification-feedback.js.map +1 -1
  87. package/dist/verify-reconciliation.d.ts +16 -1
  88. package/dist/verify-reconciliation.d.ts.map +1 -1
  89. package/dist/verify-reconciliation.js +18 -2
  90. package/dist/verify-reconciliation.js.map +1 -1
  91. package/dist/verify-restatement.d.ts +7 -0
  92. package/dist/verify-restatement.d.ts.map +1 -1
  93. package/dist/verify-restatement.js +1 -0
  94. package/dist/verify-restatement.js.map +1 -1
  95. package/dist/version-check.d.ts +6 -0
  96. package/dist/version-check.d.ts.map +1 -1
  97. package/dist/version-check.js +1 -1
  98. package/dist/version-check.js.map +1 -1
  99. package/package.json +2 -2
  100. package/dist/drift-ratify-loop.d.ts +0 -68
  101. package/dist/drift-ratify-loop.d.ts.map +0 -1
  102. package/dist/drift-ratify-loop.js +0 -161
  103. package/dist/drift-ratify-loop.js.map +0 -1
  104. package/dist/negative-branch.d.ts +0 -136
  105. package/dist/negative-branch.d.ts.map +0 -1
  106. package/dist/negative-branch.js +0 -241
  107. package/dist/negative-branch.js.map +0 -1
  108. package/dist/shortfall-disposition-config.d.ts +0 -34
  109. package/dist/shortfall-disposition-config.d.ts.map +0 -1
  110. package/dist/shortfall-disposition-config.js +0 -46
  111. package/dist/shortfall-disposition-config.js.map +0 -1
  112. package/dist/shortfall-disposition-loop.d.ts +0 -86
  113. package/dist/shortfall-disposition-loop.d.ts.map +0 -1
  114. package/dist/shortfall-disposition-loop.js +0 -309
  115. package/dist/shortfall-disposition-loop.js.map +0 -1
@@ -1,86 +0,0 @@
1
- /**
2
- * Scoped shortfall-disposition pass.
3
- *
4
- * A focus carrying an undisposed shortfall cannot converge: the completion gate
5
- * (review-exit-phase) withholds done until every shortfall is ratified or
6
- * dismissed. A hold with no self-heal is just a wedge, so this tick finds held
7
- * focuses and arms a one-shot pass whose ONLY mandate is disposing them.
8
- *
9
- * WHY A TICK AND NOT THE REVIEW-EXIT PATH. The mandate covers shortfalls a
10
- * review missed AND ones that arrived after the review window closed. A late
11
- * arrival coincides with no review exit at all -- no handler runs to notice it --
12
- * so arming from the exit path could only ever cover half the job. A tick sees a
13
- * held focus whenever it becomes held, regardless of what held it.
14
- *
15
- * WHAT THIS PASS CAN AND CANNOT DO. It runs as a CODING session (a 'review'
16
- * sessionType would re-enter the review-exit handler on exit and re-trigger the
17
- * whole auto-approve evaluation -- a spawn loop). product-api refuses an agent
18
- * shortfall-RATIFY unless it carries a review session, so this pass structurally
19
- * cannot ratify. That is deliberate, not a limitation to work around: a pass
20
- * that cannot lower a bar is a safe pass. It disposes the common case (the work
21
- * fell short -> file defects + dismiss) and deliberately LEAVES a
22
- * genuinely-wrong claim undisposed for a real review or an operator. The stall
23
- * detector bounds that tail.
24
- *
25
- * Activation: opt-out via TELORA_SHORTFALL_DISPOSITION_LOOP=0. See
26
- * `shouldRunLoop()` in focus-engine.ts.
27
- *
28
- * @module shortfall-disposition-loop
29
- */
30
- import type { DaemonConfig, StageDirective } from './types.js';
31
- import { getActiveFocuses } from './queries/deliveries.js';
32
- import { listOpenShortfallProposalIds } from './queries/reality-tree.js';
33
- import { setShortfallDispositionAttempts } from './queries/focuses.js';
34
- import { createEscalation, hasOpenFocusEscalation } from './queries/issues.js';
35
- import { hasPendingSpawnDirective } from './directive/directive-queue.js';
36
- import { assembleDirectiveContent } from './directive/directive-assembly.js';
37
- /**
38
- * The one-shot mandate. Pure + unit-testable.
39
- *
40
- * States the RULE only; the drift.shortfall_proposals resolver carries the DATA
41
- * (ids, claims, both dispositions, the exact params). Duplicating the detail
42
- * here would drift from the resolver.
43
- */
44
- export declare function buildShortfallDispositionDirective(): StageDirective;
45
- export interface ShortfallDispositionTickResult {
46
- productsScanned: number;
47
- focusesScanned: number;
48
- /** Focuses carrying at least one undisposed shortfall. */
49
- focusesHeld: number;
50
- /** Disposition directives armed this tick. */
51
- armed: number;
52
- /** Held focuses skipped: a team is already running or a directive is pending. */
53
- skippedBusy: number;
54
- /** Focuses that exhausted the attempt bound and were escalated to an operator. */
55
- escalated: number;
56
- /** Focuses whose attempt counter was reset because their shortfalls cleared. */
57
- countersReset: number;
58
- errors: number;
59
- }
60
- export interface ShortfallDispositionDeps {
61
- getActiveFocuses: typeof getActiveFocuses;
62
- listOpenShortfallProposalIds: typeof listOpenShortfallProposalIds;
63
- /** True when a team is already running for the focus. */
64
- hasActiveTeam: (focusId: string) => boolean;
65
- hasPendingSpawnDirective: typeof hasPendingSpawnDirective;
66
- assembleDirectiveContent: typeof assembleDirectiveContent;
67
- /** Stash the directive for the spawner to consume. */
68
- armDirective: (focusId: string, message: string, directive: StageDirective) => void;
69
- /** Persist the durable attempt counter. */
70
- setShortfallDispositionAttempts: typeof setShortfallDispositionAttempts;
71
- /** Per-focus dedup so the cap files exactly one open escalation. */
72
- hasOpenFocusEscalation: typeof hasOpenFocusEscalation;
73
- createEscalation: typeof createEscalation;
74
- /** Injectable so the pure decision unit-tests without env or Supabase. */
75
- cap?: number;
76
- }
77
- /**
78
- * Run one disposition-pass tick across every product in the daemon config.
79
- *
80
- * Arms at most one directive per held focus per tick, and never while a team is
81
- * running or a directive is already pending -- so a focus that stays held across
82
- * ticks does not accumulate spawns. Per-focus failures are counted and skipped;
83
- * one unresolvable focus must not stop the others.
84
- */
85
- export declare function runShortfallDispositionTick(config: DaemonConfig, depOverrides?: Partial<ShortfallDispositionDeps>): Promise<ShortfallDispositionTickResult>;
86
- //# sourceMappingURL=shortfall-disposition-loop.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shortfall-disposition-loop.d.ts","sourceRoot":"","sources":["../src/shortfall-disposition-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACL,wBAAwB,EAGzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AA0B7E;;;;;;GAMG;AACH,wBAAgB,kCAAkC,IAAI,cAAc,CA0CnE;AAED,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,4BAA4B,EAAE,OAAO,4BAA4B,CAAC;IAClE,yDAAyD;IACzD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,wBAAwB,EAAE,OAAO,wBAAwB,CAAC;IAC1D,sDAAsD;IACtD,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;IACpF,2CAA2C;IAC3C,+BAA+B,EAAE,OAAO,+BAA+B,CAAC;IACxE,oEAAoE;IACpE,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAgGD;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,YAAY,EACpB,YAAY,GAAE,OAAO,CAAC,wBAAwB,CAAM,GACnD,OAAO,CAAC,8BAA8B,CAAC,CAuIzC"}
@@ -1,309 +0,0 @@
1
- /**
2
- * Scoped shortfall-disposition pass.
3
- *
4
- * A focus carrying an undisposed shortfall cannot converge: the completion gate
5
- * (review-exit-phase) withholds done until every shortfall is ratified or
6
- * dismissed. A hold with no self-heal is just a wedge, so this tick finds held
7
- * focuses and arms a one-shot pass whose ONLY mandate is disposing them.
8
- *
9
- * WHY A TICK AND NOT THE REVIEW-EXIT PATH. The mandate covers shortfalls a
10
- * review missed AND ones that arrived after the review window closed. A late
11
- * arrival coincides with no review exit at all -- no handler runs to notice it --
12
- * so arming from the exit path could only ever cover half the job. A tick sees a
13
- * held focus whenever it becomes held, regardless of what held it.
14
- *
15
- * WHAT THIS PASS CAN AND CANNOT DO. It runs as a CODING session (a 'review'
16
- * sessionType would re-enter the review-exit handler on exit and re-trigger the
17
- * whole auto-approve evaluation -- a spawn loop). product-api refuses an agent
18
- * shortfall-RATIFY unless it carries a review session, so this pass structurally
19
- * cannot ratify. That is deliberate, not a limitation to work around: a pass
20
- * that cannot lower a bar is a safe pass. It disposes the common case (the work
21
- * fell short -> file defects + dismiss) and deliberately LEAVES a
22
- * genuinely-wrong claim undisposed for a real review or an operator. The stall
23
- * detector bounds that tail.
24
- *
25
- * Activation: opt-out via TELORA_SHORTFALL_DISPOSITION_LOOP=0. See
26
- * `shouldRunLoop()` in focus-engine.ts.
27
- *
28
- * @module shortfall-disposition-loop
29
- */
30
- import { withRetry, ESCALATION_REASONS, ESCALATION_DISPOSITIONS } from '@telora/daemon-core';
31
- import { configForProduct } from './config.js';
32
- import { getActiveFocuses } from './queries/deliveries.js';
33
- import { listOpenShortfallProposalIds } from './queries/reality-tree.js';
34
- import { setShortfallDispositionAttempts } from './queries/focuses.js';
35
- import { createEscalation, hasOpenFocusEscalation } from './queries/issues.js';
36
- import { getActiveTeams } from './focus-team-state.js';
37
- import { hasPendingSpawnDirective, pendingSpawnDirectives, computeDirectiveHash, } from './directive/directive-queue.js';
38
- import { assembleDirectiveContent } from './directive/directive-assembly.js';
39
- import { resolveShortfallDispositionAttemptCap } from './shortfall-disposition-config.js';
40
- import { createLogger } from './log.js';
41
- const log = createLogger({ module: 'shortfall-disposition-loop' });
42
- /**
43
- * Declared daemon-locally, not imported from @telora/daemon-core's EscalationKind
44
- * union. That union is registry-published and lags the DB CHECK by several
45
- * values, so it cannot name this kind until a publish lands. The DB CHECK
46
- * (20260715231941) is the real constraint. Same workaround stall-detectors.ts
47
- * documents.
48
- */
49
- const SHORTFALL_UNDISPOSED_KIND = 'shortfall_undisposed';
50
- /**
51
- * Deliberately narrow. The pass needs the shortfalls (with their ids, claims,
52
- * and what reality showed -- all rendered by the resolver) and the diff that
53
- * produced them. Nothing else: a wider recipe invites the pass to re-adjudicate
54
- * work that is not its mandate.
55
- */
56
- const SHORTFALL_DISPOSITION_ASSEMBLY = [
57
- 'drift.shortfall_proposals',
58
- 'git.diff_against_base',
59
- ];
60
- /**
61
- * The one-shot mandate. Pure + unit-testable.
62
- *
63
- * States the RULE only; the drift.shortfall_proposals resolver carries the DATA
64
- * (ids, claims, both dispositions, the exact params). Duplicating the detail
65
- * here would drift from the resolver.
66
- */
67
- export function buildShortfallDispositionDirective() {
68
- return {
69
- execution: 'spawn',
70
- compact: null,
71
- assembly: [...SHORTFALL_DISPOSITION_ASSEMBLY],
72
- tools: null,
73
- prompt: [
74
- 'You are a scoped disposition pass. This focus cannot finish because it',
75
- 'carries shortfall drift proposals nobody has disposed. Disposing them is',
76
- 'your ONLY mandate -- do not review the code, do not refactor, do not pick',
77
- 'up other work.',
78
- '',
79
- 'A shortfall says: the reality tree claimed something, and the work',
80
- 'delivered less than that claim. One of the two was wrong, and until',
81
- 'someone says which, no delivery on this focus can converge to done.',
82
- '',
83
- 'The proposals awaiting you are listed in your context, each with its id,',
84
- 'the claim, and what reality showed. For EACH one:',
85
- '',
86
- '- **The WORK fell short** (the common case) -- file a defect issue on the',
87
- ' delivery that owns the gap (`telora_product_issue` action=create, type',
88
- ' Bug or Task, with a concrete title/description the coding team can act',
89
- ' on), THEN dismiss the proposal via `telora_reality_drift`',
90
- ' action=dismiss with a non-empty `reason` naming the issues you filed.',
91
- ' Dismissing REJECTS the proposed correction: the claim stands, and the',
92
- ' work is what changes. Filing the defect ALONE is not a disposition --',
93
- ' it leaves the proposal open and the focus stays wedged.',
94
- '',
95
- '- **The CLAIM was wrong** -- the tree asserted something it should never',
96
- ' have asserted. You CANNOT dispose this case: amending a claim requires',
97
- ' an independent review session, and you are not one. Do NOT dismiss it',
98
- ' to clear the queue -- dismissing asserts the claim stands, which would',
99
- ' be a false statement about reality. LEAVE IT UNDISPOSED and say so',
100
- ' plainly in your final message, naming the proposal id and why you',
101
- ' believe the claim is wrong. An operator will be escalated to.',
102
- '',
103
- 'Never dismiss a proposal you have not actually understood. An unexplained',
104
- 'dismissal discards the signal the loop exists to carry, and the dismiss',
105
- 'rate is measured.',
106
- ].join('\n'),
107
- model: null,
108
- };
109
- }
110
- function defaultArmDirective(focusId, message, directive) {
111
- pendingSpawnDirectives.set(focusId, {
112
- message,
113
- model: directive.model ?? null,
114
- // Fixed-purpose one-shot: the focus's model selector must not override it.
115
- focusOverrideModel: null,
116
- // MUST be 'coding'. A 'review' sessionType re-enters runReviewExitHandler on
117
- // exit and re-triggers the auto-approve evaluation -- a spawn loop. The
118
- // close_loop bookkeeper sets 'coding' for exactly this reason.
119
- sessionType: 'coding',
120
- // Its own lineage slot: cannot resume or clobber the coder's or reviewer's
121
- // context (session-lineage.ts:53-70).
122
- lineage: 'shortfall_disposition',
123
- continuity: 'fresh',
124
- contentHash: computeDirectiveHash(directive),
125
- });
126
- }
127
- function defaultDeps() {
128
- return {
129
- getActiveFocuses,
130
- listOpenShortfallProposalIds,
131
- hasActiveTeam: (focusId) => getActiveTeams().has(focusId),
132
- hasPendingSpawnDirective,
133
- assembleDirectiveContent,
134
- armDirective: defaultArmDirective,
135
- setShortfallDispositionAttempts,
136
- hasOpenFocusEscalation,
137
- createEscalation,
138
- };
139
- }
140
- /**
141
- * File the one escalation that lets a human into this loop.
142
- *
143
- * Deduped per focus against the DB (not memory), so the bound holds across a
144
- * daemon restart and a held focus accrues exactly one open escalation.
145
- */
146
- async function escalateUndisposed(deps, params) {
147
- if (await deps.hasOpenFocusEscalation(params.focusId, SHORTFALL_UNDISPOSED_KIND)) {
148
- return false;
149
- }
150
- await withRetry(() => deps.createEscalation({
151
- organizationId: params.organizationId,
152
- sessionId: '',
153
- issueId: null,
154
- reasonType: ESCALATION_REASONS.BLOCKED_BY_EXTERNAL,
155
- disposition: ESCALATION_DISPOSITIONS.NEEDS_OPERATOR,
156
- anchor: { focusId: params.focusId },
157
- escalationKind: SHORTFALL_UNDISPOSED_KIND,
158
- description: `Focus "${params.focusName}" cannot finish: ${params.shortfallIds.length} shortfall ` +
159
- `drift proposal(s) are still undisposed after ${params.attempts} disposition pass(es) ` +
160
- `(cap ${params.cap}). Its deliveries are held in verify and the loop will not ` +
161
- `converge on its own.\n\n` +
162
- `**Focus:** ${params.focusName}\n` +
163
- `**Focus ID:** ${params.focusId}\n` +
164
- `**Undisposed proposals:** ${params.shortfallIds.join(', ')}\n\n` +
165
- `A shortfall means the reality tree claimed something and the work delivered less ` +
166
- `than that claim. One of the two is wrong, and the machine could not decide which.\n\n` +
167
- `The likeliest cause is that the CLAIM is wrong: the disposition pass runs as a ` +
168
- `coding session and CANNOT ratify (amending a claim requires an independent review ` +
169
- `session), so it correctly left these alone rather than dismissing them falsely.`,
170
- whatWasTried: `${params.attempts} scoped disposition pass(es) were armed. Each could file defects ` +
171
- `and dismiss a proposal whose CLAIM stands, but none disposed these.`,
172
- helpNeeded: `Decide, per proposal: if the CLAIM was wrong, ratify it (with a rationale) so the ` +
173
- `tree amends; if the WORK fell short, dismiss it (with a reason) and ensure defect ` +
174
- `issues exist so the delivery re-codes. Either disposition clears the hold.`,
175
- metadata: {
176
- cause: SHORTFALL_UNDISPOSED_KIND,
177
- focusName: params.focusName,
178
- shortfallProposalIds: params.shortfallIds,
179
- attempts: params.attempts,
180
- cap: params.cap,
181
- },
182
- }), { maxAttempts: 3, label: `escalation-shortfall-undisposed-${params.focusId}` });
183
- return true;
184
- }
185
- /**
186
- * Run one disposition-pass tick across every product in the daemon config.
187
- *
188
- * Arms at most one directive per held focus per tick, and never while a team is
189
- * running or a directive is already pending -- so a focus that stays held across
190
- * ticks does not accumulate spawns. Per-focus failures are counted and skipped;
191
- * one unresolvable focus must not stop the others.
192
- */
193
- export async function runShortfallDispositionTick(config, depOverrides = {}) {
194
- const deps = { ...defaultDeps(), ...depOverrides };
195
- const cap = deps.cap ?? resolveShortfallDispositionAttemptCap();
196
- const counts = {
197
- productsScanned: 0,
198
- focusesScanned: 0,
199
- focusesHeld: 0,
200
- armed: 0,
201
- skippedBusy: 0,
202
- escalated: 0,
203
- countersReset: 0,
204
- errors: 0,
205
- };
206
- for (const product of config.products) {
207
- counts.productsScanned += 1;
208
- const pc = configForProduct(config, product);
209
- let focuses;
210
- try {
211
- focuses = await deps.getActiveFocuses(config.organizationId, product.id);
212
- }
213
- catch (err) {
214
- counts.errors += 1;
215
- log.warn(`[shortfall-disposition] getActiveFocuses failed for product ${product.id}: ${err.message}`);
216
- continue;
217
- }
218
- for (const focus of focuses) {
219
- counts.focusesScanned += 1;
220
- let shortfallIds;
221
- try {
222
- shortfallIds = await deps.listOpenShortfallProposalIds(focus.focus_id);
223
- }
224
- catch (err) {
225
- counts.errors += 1;
226
- log.warn(`[shortfall-disposition] shortfall lookup failed for "${focus.focus_name}": ${err.message}`);
227
- continue;
228
- }
229
- const attempts = focus.shortfall_disposition_attempts ?? 0;
230
- if (shortfallIds.length === 0) {
231
- // Cleared. Reset the budget so a later, unrelated shortfall gets a full
232
- // set of attempts rather than inheriting an exhausted counter.
233
- if (attempts > 0) {
234
- try {
235
- await deps.setShortfallDispositionAttempts(focus.focus_id, 0);
236
- counts.countersReset += 1;
237
- }
238
- catch (err) {
239
- counts.errors += 1;
240
- log.warn(`[shortfall-disposition] failed to reset attempts for "${focus.focus_name}": ${err.message}`);
241
- }
242
- }
243
- continue;
244
- }
245
- counts.focusesHeld += 1;
246
- // The bound. Past the cap the machine has demonstrably failed to dispose
247
- // these on its own, so stop arming (each pass costs a team) and hand it to
248
- // an operator instead. The counter is DURABLE, so this survives restarts:
249
- // an in-process counter would reset and re-arm forever, never escalating.
250
- if (attempts >= cap) {
251
- try {
252
- if (await escalateUndisposed(deps, {
253
- organizationId: config.organizationId,
254
- focusId: focus.focus_id,
255
- focusName: focus.focus_name,
256
- shortfallIds,
257
- attempts,
258
- cap,
259
- })) {
260
- counts.escalated += 1;
261
- log.info(`[shortfall-disposition] filed ${SHORTFALL_UNDISPOSED_KIND} for "${focus.focus_name}" ` +
262
- `(${shortfallIds.length} undisposed after ${attempts} pass(es), cap ${cap})`);
263
- }
264
- }
265
- catch (err) {
266
- counts.errors += 1;
267
- log.warn(`[shortfall-disposition] failed to escalate for "${focus.focus_name}": ${err.message}`);
268
- }
269
- continue;
270
- }
271
- // A running team already has (or will get) the context; a pending
272
- // directive is already queued for the spawner. Arming over either would
273
- // duplicate work or clobber a queued handoff.
274
- if (deps.hasActiveTeam(focus.focus_id) || deps.hasPendingSpawnDirective(focus.focus_id)) {
275
- counts.skippedBusy += 1;
276
- continue;
277
- }
278
- try {
279
- const directive = buildShortfallDispositionDirective();
280
- // No worktree path: the pass is armed between teams, so there is no live
281
- // team to read one from. git.diff_against_base degrades to nothing
282
- // rather than throwing (assembly sources fail soft), and the shortfall
283
- // section -- the part that matters -- resolves regardless.
284
- const message = await deps.assembleDirectiveContent(pc, focus.focus_id, directive, null);
285
- deps.armDirective(focus.focus_id, message, directive);
286
- counts.armed += 1;
287
- // Count the attempt AFTER the arm succeeds -- an assembly failure is not
288
- // an attempt, and charging for it would burn the budget without the pass
289
- // ever running. Persisted before the next tick can read it, so the bound
290
- // advances even if this process dies immediately after.
291
- await deps.setShortfallDispositionAttempts(focus.focus_id, attempts + 1);
292
- log.info(`[shortfall-disposition] armed a disposition pass for "${focus.focus_name}" ` +
293
- `(attempt ${attempts + 1}/${cap}, ${shortfallIds.length} undisposed shortfall(s): ` +
294
- `${shortfallIds.join(', ')})`);
295
- }
296
- catch (err) {
297
- counts.errors += 1;
298
- log.warn(`[shortfall-disposition] failed to arm for "${focus.focus_name}": ${err.message}`);
299
- }
300
- }
301
- }
302
- if (counts.focusesHeld > 0 || counts.errors > 0) {
303
- log.info(`[shortfall-disposition] tick: products=${counts.productsScanned} focuses=${counts.focusesScanned} ` +
304
- `held=${counts.focusesHeld} armed=${counts.armed} skippedBusy=${counts.skippedBusy} ` +
305
- `escalated=${counts.escalated} reset=${counts.countersReset} errors=${counts.errors}`);
306
- }
307
- return counts;
308
- }
309
- //# sourceMappingURL=shortfall-disposition-loop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shortfall-disposition-loop.js","sourceRoot":"","sources":["../src/shortfall-disposition-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,qCAAqC,EAAE,MAAM,mCAAmC,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,yBAAyB,GAAG,sBAAsB,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,8BAA8B,GAAsB;IACxD,2BAA2B;IAC3B,uBAAuB;CACxB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,kCAAkC;IAChD,OAAO;QACL,SAAS,EAAE,OAAO;QAClB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,CAAC,GAAG,8BAA8B,CAAC;QAC7C,KAAK,EAAE,IAAI;QACX,MAAM,EAAE;YACN,wEAAwE;YACxE,0EAA0E;YAC1E,2EAA2E;YAC3E,gBAAgB;YAChB,EAAE;YACF,oEAAoE;YACpE,qEAAqE;YACrE,qEAAqE;YACrE,EAAE;YACF,0EAA0E;YAC1E,mDAAmD;YACnD,EAAE;YACF,2EAA2E;YAC3E,0EAA0E;YAC1E,0EAA0E;YAC1E,6DAA6D;YAC7D,yEAAyE;YACzE,yEAAyE;YACzE,yEAAyE;YACzE,2DAA2D;YAC3D,EAAE;YACF,0EAA0E;YAC1E,0EAA0E;YAC1E,yEAAyE;YACzE,0EAA0E;YAC1E,sEAAsE;YACtE,qEAAqE;YACrE,iEAAiE;YACjE,EAAE;YACF,2EAA2E;YAC3E,yEAAyE;YACzE,mBAAmB;SACpB,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,KAAK,EAAE,IAAI;KACZ,CAAC;AACJ,CAAC;AAoCD,SAAS,mBAAmB,CAAC,OAAe,EAAE,OAAe,EAAE,SAAyB;IACtF,sBAAsB,CAAC,GAAG,CAAC,OAAO,EAAE;QAClC,OAAO;QACP,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,IAAI;QAC9B,2EAA2E;QAC3E,kBAAkB,EAAE,IAAI;QACxB,6EAA6E;QAC7E,wEAAwE;QACxE,+DAA+D;QAC/D,WAAW,EAAE,QAAQ;QACrB,2EAA2E;QAC3E,sCAAsC;QACtC,OAAO,EAAE,uBAAuB;QAChC,UAAU,EAAE,OAAO;QACnB,WAAW,EAAE,oBAAoB,CAAC,SAAS,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;QACL,gBAAgB;QAChB,4BAA4B;QAC5B,aAAa,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,cAAc,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;QACjE,wBAAwB;QACxB,wBAAwB;QACxB,YAAY,EAAE,mBAAmB;QACjC,+BAA+B;QAC/B,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,kBAAkB,CAC/B,IAA8B,EAC9B,MAOC;IAED,IAAI,MAAM,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,EAAE,yBAAyB,CAAC,EAAE,CAAC;QACjF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,SAAS,CACb,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,kBAAkB,CAAC,mBAAmB;QAClD,WAAW,EAAE,uBAAuB,CAAC,cAAc;QACnD,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE;QACnC,cAAc,EAAE,yBAAyB;QACzC,WAAW,EACT,UAAU,MAAM,CAAC,SAAS,oBAAoB,MAAM,CAAC,YAAY,CAAC,MAAM,aAAa;YACrF,gDAAgD,MAAM,CAAC,QAAQ,wBAAwB;YACvF,QAAQ,MAAM,CAAC,GAAG,6DAA6D;YAC/E,0BAA0B;YAC1B,cAAc,MAAM,CAAC,SAAS,IAAI;YAClC,iBAAiB,MAAM,CAAC,OAAO,IAAI;YACnC,6BAA6B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YACjE,mFAAmF;YACnF,uFAAuF;YACvF,iFAAiF;YACjF,oFAAoF;YACpF,iFAAiF;QACnF,YAAY,EACV,GAAG,MAAM,CAAC,QAAQ,mEAAmE;YACrF,qEAAqE;QACvE,UAAU,EACR,oFAAoF;YACpF,oFAAoF;YACpF,4EAA4E;QAC9E,QAAQ,EAAE;YACR,KAAK,EAAE,yBAAyB;YAChC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,oBAAoB,EAAE,MAAM,CAAC,YAAY;YACzC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,EAAE,MAAM,CAAC,GAAG;SAChB;KACF,CAAC,EACF,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,mCAAmC,MAAM,CAAC,OAAO,EAAE,EAAE,CAC/E,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAoB,EACpB,eAAkD,EAAE;IAEpD,MAAM,IAAI,GAA6B,EAAE,GAAG,WAAW,EAAE,EAAE,GAAG,YAAY,EAAE,CAAC;IAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,qCAAqC,EAAE,CAAC;IAChE,MAAM,MAAM,GAAmC;QAC7C,eAAe,EAAE,CAAC;QAClB,cAAc,EAAE,CAAC;QACjB,WAAW,EAAE,CAAC;QACd,KAAK,EAAE,CAAC;QACR,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,aAAa,EAAE,CAAC;QAChB,MAAM,EAAE,CAAC;KACV,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;QAC5B,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE7C,IAAI,OAAqD,CAAC;QAC1D,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;YACnB,GAAG,CAAC,IAAI,CACN,+DAA+D,OAAO,CAAC,EAAE,KAAM,GAAa,CAAC,OAAO,EAAE,CACvG,CAAC;YACF,SAAS;QACX,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC;YAE3B,IAAI,YAAsB,CAAC;YAC3B,IAAI,CAAC;gBACH,YAAY,GAAG,MAAM,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACzE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;gBACnB,GAAG,CAAC,IAAI,CACN,wDAAwD,KAAK,CAAC,UAAU,MAAO,GAAa,CAAC,OAAO,EAAE,CACvG,CAAC;gBACF,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,KAAK,CAAC,8BAA8B,IAAI,CAAC,CAAC;YAE3D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,wEAAwE;gBACxE,+DAA+D;gBAC/D,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;oBACjB,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,+BAA+B,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;wBAC9D,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;oBAC5B,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;wBACnB,GAAG,CAAC,IAAI,CACN,yDAAyD,KAAK,CAAC,UAAU,MAAO,GAAa,CAAC,OAAO,EAAE,CACxG,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;YAExB,yEAAyE;YACzE,2EAA2E;YAC3E,0EAA0E;YAC1E,0EAA0E;YAC1E,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC;oBACH,IAAI,MAAM,kBAAkB,CAAC,IAAI,EAAE;wBACjC,cAAc,EAAE,MAAM,CAAC,cAAc;wBACrC,OAAO,EAAE,KAAK,CAAC,QAAQ;wBACvB,SAAS,EAAE,KAAK,CAAC,UAAU;wBAC3B,YAAY;wBACZ,QAAQ;wBACR,GAAG;qBACJ,CAAC,EAAE,CAAC;wBACH,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;wBACtB,GAAG,CAAC,IAAI,CACN,iCAAiC,yBAAyB,SAAS,KAAK,CAAC,UAAU,IAAI;4BACvF,IAAI,YAAY,CAAC,MAAM,qBAAqB,QAAQ,kBAAkB,GAAG,GAAG,CAC7E,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;oBACnB,GAAG,CAAC,IAAI,CACN,mDAAmD,KAAK,CAAC,UAAU,MAAO,GAAa,CAAC,OAAO,EAAE,CAClG,CAAC;gBACJ,CAAC;gBACD,SAAS;YACX,CAAC;YAED,kEAAkE;YAClE,wEAAwE;YACxE,8CAA8C;YAC9C,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxF,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;gBACxB,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,kCAAkC,EAAE,CAAC;gBACvD,yEAAyE;gBACzE,mEAAmE;gBACnE,uEAAuE;gBACvE,2DAA2D;gBAC3D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;gBACzF,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;gBACtD,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;gBAClB,yEAAyE;gBACzE,yEAAyE;gBACzE,yEAAyE;gBACzE,wDAAwD;gBACxD,MAAM,IAAI,CAAC,+BAA+B,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;gBACzE,GAAG,CAAC,IAAI,CACN,yDAAyD,KAAK,CAAC,UAAU,IAAI;oBAC7E,YAAY,QAAQ,GAAG,CAAC,IAAI,GAAG,KAAK,YAAY,CAAC,MAAM,4BAA4B;oBACnF,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9B,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;gBACnB,GAAG,CAAC,IAAI,CACN,8CAA8C,KAAK,CAAC,UAAU,MAAO,GAAa,CAAC,OAAO,EAAE,CAC7F,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,IAAI,CACN,0CAA0C,MAAM,CAAC,eAAe,YAAY,MAAM,CAAC,cAAc,GAAG;YACpG,QAAQ,MAAM,CAAC,WAAW,UAAU,MAAM,CAAC,KAAK,gBAAgB,MAAM,CAAC,WAAW,GAAG;YACrF,aAAa,MAAM,CAAC,SAAS,UAAU,MAAM,CAAC,aAAa,WAAW,MAAM,CAAC,MAAM,EAAE,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}