@ai-dossier/sched 0.57.4 → 0.57.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/batch-dispatch.d.ts +1 -1
- package/dist/batch-dispatch.d.ts.map +1 -1
- package/dist/batch-dispatch.js +22 -16
- package/dist/batch-dispatch.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +83 -74
- package/dist/engine.js.map +1 -1
- package/dist/state.d.ts +18 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +25 -0
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +16 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAmB,MAAM,kBAAkB,CAAC;AAE3E,OAAO,EAcL,KAAK,SAAS,EAKf,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE3E,OAAO,EACL,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAe,KAAK,OAAO,EAAa,MAAM,WAAW,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -1397,6 +1397,24 @@ function journalMilestoneProgressIfDue(ctx, state, slotId, milestone, unit, now,
|
|
|
1397
1397
|
function effectiveClosedSignal(slot, truth) {
|
|
1398
1398
|
return (0, state_1.isReportSlot)(slot) ? false : truth.closed;
|
|
1399
1399
|
}
|
|
1400
|
+
/**
|
|
1401
|
+
* The `QueueEntry` fields backing each entry-rail dedup event (#638): one
|
|
1402
|
+
* descriptor per event instead of accessor lambdas, so `journalConditionIfDue`
|
|
1403
|
+
* and `clearCondition` are single bodies. `condition` names the streak
|
|
1404
|
+
* discriminator field (#637), or `null` for a presence-only streak.
|
|
1405
|
+
*/
|
|
1406
|
+
const ENTRY_DEDUP_MARKERS = {
|
|
1407
|
+
'ground-truth-unreachable': {
|
|
1408
|
+
since: 'ground_truth_unreachable_since',
|
|
1409
|
+
ticks: 'ground_truth_unreachable_ticks',
|
|
1410
|
+
condition: 'ground_truth_unreachable_condition',
|
|
1411
|
+
},
|
|
1412
|
+
'pr-watch-waiting': {
|
|
1413
|
+
since: 'pr_watch_waiting_since',
|
|
1414
|
+
ticks: 'pr_watch_waiting_ticks',
|
|
1415
|
+
condition: null,
|
|
1416
|
+
},
|
|
1417
|
+
};
|
|
1400
1418
|
/**
|
|
1401
1419
|
* Journal `event` for `unit` on the first tick of a new streak, then again
|
|
1402
1420
|
* only every `JOURNAL_DEDUP_REANNOUNCE_TICKS` ticks while it persists (#632).
|
|
@@ -1426,23 +1444,27 @@ function effectiveClosedSignal(slot, truth) {
|
|
|
1426
1444
|
* Returns the patched state — callers must thread it, or the marker is lost
|
|
1427
1445
|
* and the event re-fires next tick as if nothing had been recorded.
|
|
1428
1446
|
*/
|
|
1429
|
-
function journalConditionIfDue(ctx, state, unit, event,
|
|
1447
|
+
function journalConditionIfDue(ctx, state, unit, event, condition, extra) {
|
|
1430
1448
|
const issue = (0, journal_1.issueOfUnit)(unit);
|
|
1431
1449
|
const entry = issue === null ? undefined : (0, state_1.findEntry)(state, issue);
|
|
1432
1450
|
if (issue === null || entry === undefined) {
|
|
1433
1451
|
journal(ctx, event, unit, extra);
|
|
1434
1452
|
return state;
|
|
1435
1453
|
}
|
|
1436
|
-
const
|
|
1437
|
-
const ticks = isNewStreak ? 1 : ticksOf(entry) + 1;
|
|
1454
|
+
const marker = ENTRY_DEDUP_MARKERS[event];
|
|
1438
1455
|
const now = ctx.deps.now();
|
|
1439
|
-
|
|
1440
|
-
|
|
1456
|
+
// #637: identity is the condition key + presence — a different key on the
|
|
1457
|
+
// same unit starts a new streak. Events without a discriminator
|
|
1458
|
+
// (`pr-watch-waiting`) are presence-only.
|
|
1459
|
+
const changed = marker.condition !== null && entry[marker.condition] !== condition;
|
|
1460
|
+
const { since, ticks, announce } = (0, state_1.advanceStreak)({ since: entry[marker.since], ticks: entry[marker.ticks] }, changed, now);
|
|
1461
|
+
if (announce) {
|
|
1441
1462
|
// `at` is the decision clock (AC3); `since` is the streak's onset. Both
|
|
1442
1463
|
// are needed: `ticks_persisted` is a TICK count, and the two rails tick at
|
|
1443
1464
|
// different, operator-tunable rates, so it maps to no fixed wall-clock.
|
|
1444
1465
|
journal(ctx, event, unit, {
|
|
1445
1466
|
...extra,
|
|
1467
|
+
...(condition !== null ? { condition } : {}),
|
|
1446
1468
|
at: now.toISOString(),
|
|
1447
1469
|
since,
|
|
1448
1470
|
ticks_persisted: ticks,
|
|
@@ -1453,39 +1475,29 @@ function journalConditionIfDue(ctx, state, unit, event, sinceOf, ticksOf, withMa
|
|
|
1453
1475
|
// elsewhere (`isStaleFailedPark`'s window, `status.ts`'s "since" display,
|
|
1454
1476
|
// `readiness.ts`'s dispatch tiebreak) as a clock that must not reset on a
|
|
1455
1477
|
// silent tick.
|
|
1456
|
-
return (0, state_1.patchEntry)(state, issue,
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
ground_truth_unreachable_ticks: ticks,
|
|
1462
|
-
}), extra);
|
|
1463
|
-
}
|
|
1464
|
-
function journalPrWatchWaitingIfDue(ctx, state, unit, extra) {
|
|
1465
|
-
return journalConditionIfDue(ctx, state, unit, 'pr-watch-waiting', (e) => e.pr_watch_waiting_since, (e) => e.pr_watch_waiting_ticks, (since, ticks) => ({ pr_watch_waiting_since: since, pr_watch_waiting_ticks: ticks }), extra);
|
|
1478
|
+
return (0, state_1.patchEntry)(state, issue, {
|
|
1479
|
+
[marker.since]: since,
|
|
1480
|
+
[marker.ticks]: ticks,
|
|
1481
|
+
...(marker.condition !== null ? { [marker.condition]: condition } : {}),
|
|
1482
|
+
}, now, false);
|
|
1466
1483
|
}
|
|
1467
1484
|
/**
|
|
1468
|
-
* Clear a `QueueEntry`'s `
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1485
|
+
* Clear a `QueueEntry`'s `event` dedup marker once the condition resolves
|
|
1486
|
+
* (#632) — a no-op when nothing was set, so callers can call this
|
|
1487
|
+
* unconditionally on every tick the condition is healthy without churning
|
|
1471
1488
|
* `updated_at` for entries that were never in a streak.
|
|
1472
1489
|
*/
|
|
1473
|
-
function
|
|
1474
|
-
const issue = (0, journal_1.issueOfUnit)(unit);
|
|
1475
|
-
const entry = issue === null ? undefined : (0, state_1.findEntry)(state, issue);
|
|
1476
|
-
if (issue === null || entry === undefined || entry.ground_truth_unreachable_since === null) {
|
|
1477
|
-
return state;
|
|
1478
|
-
}
|
|
1479
|
-
return (0, state_1.patchEntry)(state, issue, { ground_truth_unreachable_since: null, ground_truth_unreachable_ticks: 0 }, now, false);
|
|
1480
|
-
}
|
|
1481
|
-
/** Same as `clearGroundTruthUnreachable`, for the `pr-watch-waiting` marker. */
|
|
1482
|
-
function clearPrWatchWaiting(state, unit, now) {
|
|
1490
|
+
function clearCondition(state, unit, event, now) {
|
|
1483
1491
|
const issue = (0, journal_1.issueOfUnit)(unit);
|
|
1484
1492
|
const entry = issue === null ? undefined : (0, state_1.findEntry)(state, issue);
|
|
1485
|
-
|
|
1493
|
+
const marker = ENTRY_DEDUP_MARKERS[event];
|
|
1494
|
+
if (issue === null || entry === undefined || entry[marker.since] === null)
|
|
1486
1495
|
return state;
|
|
1487
|
-
|
|
1488
|
-
|
|
1496
|
+
return (0, state_1.patchEntry)(state, issue, {
|
|
1497
|
+
[marker.since]: null,
|
|
1498
|
+
[marker.ticks]: 0,
|
|
1499
|
+
...(marker.condition !== null ? { [marker.condition]: null } : {}),
|
|
1500
|
+
}, now, false);
|
|
1489
1501
|
}
|
|
1490
1502
|
/**
|
|
1491
1503
|
* #575: journal the ignored stale milestone — shared by `reconcileRunning`'s
|
|
@@ -1727,7 +1739,7 @@ function reconcileRunning(ctx, state, slot, truth, unit) {
|
|
|
1727
1739
|
// this unit until truth returns. The dead-pid rail above still ran — local
|
|
1728
1740
|
// truth needs no network.
|
|
1729
1741
|
if (!truth.reachable) {
|
|
1730
|
-
return
|
|
1742
|
+
return journalConditionIfDue(ctx, state, unit, 'ground-truth-unreachable', 'poll-unreachable', {
|
|
1731
1743
|
slot: slot.id,
|
|
1732
1744
|
detail: 'stall/advance decisions paused until truth returns',
|
|
1733
1745
|
});
|
|
@@ -1736,7 +1748,7 @@ function reconcileRunning(ctx, state, slot, truth, unit) {
|
|
|
1736
1748
|
// a PREVIOUS tick is over.
|
|
1737
1749
|
// Named for what it holds — a SchedState with the streak cleared — not for
|
|
1738
1750
|
// `truth.reachable`, the boolean five lines up.
|
|
1739
|
-
const cleared =
|
|
1751
|
+
const cleared = clearCondition(state, unit, 'ground-truth-unreachable', now);
|
|
1740
1752
|
// Ground truth says the unit is DONE while the agent still holds the slot —
|
|
1741
1753
|
// externally-advanced state (AC3): reclaim the slot, kill the leftover agent.
|
|
1742
1754
|
// A parked milestone is deliberately NOT an advance: a detached run parks
|
|
@@ -1875,7 +1887,7 @@ dispatchSignals = NO_DISPATCH_SIGNALS) {
|
|
|
1875
1887
|
// hold the exit in `verifying` until truth returns, then decide. The agent
|
|
1876
1888
|
// is already gone; no slot work is lost by waiting.
|
|
1877
1889
|
if (!truth.reachable) {
|
|
1878
|
-
return
|
|
1890
|
+
return journalConditionIfDue(ctx, next, unit, 'ground-truth-unreachable', 'poll-unreachable', {
|
|
1879
1891
|
slot: slot.id,
|
|
1880
1892
|
detail: 'exit verification paused until truth returns',
|
|
1881
1893
|
});
|
|
@@ -1900,10 +1912,10 @@ dispatchSignals = NO_DISPATCH_SIGNALS) {
|
|
|
1900
1912
|
// against an empty trail. Return the recorded state (the pre-#596 form
|
|
1901
1913
|
// did — `parkUnit`'s internal guard returned the state it was handed),
|
|
1902
1914
|
// not the un-recorded `next`. #632: dedup like the sibling check above
|
|
1903
|
-
// — same marker,
|
|
1904
|
-
//
|
|
1905
|
-
//
|
|
1906
|
-
return
|
|
1915
|
+
// — same marker, but a distinct condition key (#637): this branch is
|
|
1916
|
+
// reached only after `truth.reachable` held, so an unreachable-poll
|
|
1917
|
+
// streak from the previous tick must not swallow this line.
|
|
1918
|
+
return journalConditionIfDue(ctx, parked, unit, 'ground-truth-unreachable', 'parked-milestone-no-pr', {
|
|
1907
1919
|
slot: slot.id,
|
|
1908
1920
|
detail: `parked milestone (run=${truth.milestone?.run ?? 'unknown'}) carries no parseable pr= key — holding in verifying`,
|
|
1909
1921
|
});
|
|
@@ -1911,12 +1923,12 @@ dispatchSignals = NO_DISPATCH_SIGNALS) {
|
|
|
1911
1923
|
// #632: a pr= key was found — both flavors of this unit's
|
|
1912
1924
|
// ground-truth-unreachable streak (unreachable poll, unparseable pr=)
|
|
1913
1925
|
// are resolved.
|
|
1914
|
-
return parkUnit(ctx,
|
|
1926
|
+
return parkUnit(ctx, clearCondition(parked, unit, 'ground-truth-unreachable', now), unit, pr);
|
|
1915
1927
|
}
|
|
1916
1928
|
// #632: truth answered this tick and this unit isn't stuck on the
|
|
1917
1929
|
// missing-pr= edge above — any streak recorded against a PREVIOUS tick
|
|
1918
1930
|
// (either flavor) is over.
|
|
1919
|
-
next =
|
|
1931
|
+
next = clearCondition(next, unit, 'ground-truth-unreachable', now);
|
|
1920
1932
|
// #575: fence to THIS dispatch's `spawned_at` — an agent that exited having
|
|
1921
1933
|
// posted nothing new must not read as complete against the issue's
|
|
1922
1934
|
// PREVIOUS run's report milestone; it falls through to the recovery ladder
|
|
@@ -2160,18 +2172,18 @@ function reconcileParked(ctx, state, prPoll) {
|
|
|
2160
2172
|
if (!prPoll.truths.has(issue)) {
|
|
2161
2173
|
continue; // parked AFTER the poll ran (this tick) — next cadence picks it up
|
|
2162
2174
|
}
|
|
2163
|
-
next =
|
|
2175
|
+
next = journalConditionIfDue(ctx, next, unit, 'ground-truth-unreachable', 'pr-watch-paused', {
|
|
2164
2176
|
detail: 'pr watch paused until truth returns',
|
|
2165
2177
|
});
|
|
2166
2178
|
continue;
|
|
2167
2179
|
}
|
|
2168
2180
|
// #632: truth answered this tick — any unreachable streak recorded
|
|
2169
2181
|
// against a PREVIOUS tick is over.
|
|
2170
|
-
next =
|
|
2182
|
+
next = clearCondition(next, unit, 'ground-truth-unreachable', ctx.deps.now());
|
|
2171
2183
|
const failWatch = (reason) => {
|
|
2172
2184
|
journal(ctx, 'pr-watch-failed', unit, { reason, pr: entry.pr });
|
|
2173
2185
|
// #632: the watch is ending (terminal failure) — no more "waiting".
|
|
2174
|
-
return
|
|
2186
|
+
return clearCondition(failUnit(ctx, next, unit, reason), unit, 'pr-watch-waiting', ctx.deps.now());
|
|
2175
2187
|
};
|
|
2176
2188
|
// #501: MERGED is checked FIRST, before any failure rail. A PR that is
|
|
2177
2189
|
// genuinely merged is merged regardless of a leftover `auto-merge-blocked`
|
|
@@ -2185,7 +2197,7 @@ function reconcileParked(ctx, state, prPoll) {
|
|
|
2185
2197
|
// AC1: the issue must ALSO be closed (a merged PR auto-closes it) —
|
|
2186
2198
|
// until GitHub propagates, the unit stays parked and keeps watching.
|
|
2187
2199
|
if (prPoll.closed.get(issue) !== true) {
|
|
2188
|
-
next =
|
|
2200
|
+
next = journalConditionIfDue(ctx, next, unit, 'pr-watch-waiting', null, {
|
|
2189
2201
|
pr: entry.pr,
|
|
2190
2202
|
mergedAt: truth.mergedAt,
|
|
2191
2203
|
detail: 'merge seen but issue not closed — keep watching',
|
|
@@ -2193,7 +2205,7 @@ function reconcileParked(ctx, state, prPoll) {
|
|
|
2193
2205
|
continue;
|
|
2194
2206
|
}
|
|
2195
2207
|
next = (0, state_1.transitionIssue)(next, issue, 'shipped', { reason: null }, ctx.deps.now());
|
|
2196
|
-
next =
|
|
2208
|
+
next = clearCondition(next, unit, 'pr-watch-waiting', ctx.deps.now());
|
|
2197
2209
|
journal(ctx, 'merge-accepted', unit, { pr: entry.pr, mergedAt: truth.mergedAt });
|
|
2198
2210
|
ctx.result.mergeAccepted.push(unit);
|
|
2199
2211
|
continue;
|
|
@@ -2213,7 +2225,7 @@ function reconcileParked(ctx, state, prPoll) {
|
|
|
2213
2225
|
// OPEN (or mergeable UNKNOWN) — keep watching. #632: this tick's truth
|
|
2214
2226
|
// is NOT "merge seen but not closed", so a waiting streak from an
|
|
2215
2227
|
// earlier tick's merge-then-reverted flicker is over.
|
|
2216
|
-
next =
|
|
2228
|
+
next = clearCondition(next, unit, 'pr-watch-waiting', ctx.deps.now());
|
|
2217
2229
|
}
|
|
2218
2230
|
}
|
|
2219
2231
|
return next;
|
|
@@ -2250,23 +2262,23 @@ function reconcileStaleFailedParks(ctx, state, prPoll) {
|
|
|
2250
2262
|
if (!prPoll.truths.has(issue)) {
|
|
2251
2263
|
continue; // failed AFTER the poll ran this tick — next cadence picks it up
|
|
2252
2264
|
}
|
|
2253
|
-
next =
|
|
2265
|
+
next = journalConditionIfDue(ctx, next, unit, 'ground-truth-unreachable', 'stale-failure-paused', {
|
|
2254
2266
|
detail: 'stale-failure reconcile paused until truth returns',
|
|
2255
2267
|
});
|
|
2256
2268
|
continue;
|
|
2257
2269
|
}
|
|
2258
2270
|
// #632: truth answered this tick — any unreachable streak recorded
|
|
2259
2271
|
// against a PREVIOUS tick is over.
|
|
2260
|
-
next =
|
|
2272
|
+
next = clearCondition(next, unit, 'ground-truth-unreachable', ctx.deps.now());
|
|
2261
2273
|
if (!isPrMerged(truth)) {
|
|
2262
2274
|
// Still blocked/open/conflicting — stays failed. #632: not "merge seen
|
|
2263
2275
|
// but not closed" either, so a waiting streak from an earlier tick's
|
|
2264
2276
|
// merge-then-reverted flicker is over.
|
|
2265
|
-
next =
|
|
2277
|
+
next = clearCondition(next, unit, 'pr-watch-waiting', ctx.deps.now());
|
|
2266
2278
|
continue;
|
|
2267
2279
|
}
|
|
2268
2280
|
if (prPoll.closed.get(issue) !== true) {
|
|
2269
|
-
next =
|
|
2281
|
+
next = journalConditionIfDue(ctx, next, unit, 'pr-watch-waiting', null, {
|
|
2270
2282
|
pr: entry.pr,
|
|
2271
2283
|
mergedAt: truth.mergedAt,
|
|
2272
2284
|
reason: entry.reason,
|
|
@@ -2276,7 +2288,7 @@ function reconcileStaleFailedParks(ctx, state, prPoll) {
|
|
|
2276
2288
|
}
|
|
2277
2289
|
const failedAt = entry.updated_at;
|
|
2278
2290
|
next = (0, state_1.transitionIssue)(next, issue, 'shipped', { reason: null }, ctx.deps.now());
|
|
2279
|
-
next =
|
|
2291
|
+
next = clearCondition(next, unit, 'pr-watch-waiting', ctx.deps.now());
|
|
2280
2292
|
journal(ctx, 'stale-failure-reconciled', unit, {
|
|
2281
2293
|
pr: entry.pr,
|
|
2282
2294
|
mergedAt: truth.mergedAt,
|
|
@@ -2371,29 +2383,15 @@ function dispatchReportAgents(ctx, state, config) {
|
|
|
2371
2383
|
}
|
|
2372
2384
|
/**
|
|
2373
2385
|
* Run the teardown script for one merged unit OUTSIDE the state lock (#468
|
|
2374
|
-
* AC2). Returns
|
|
2375
|
-
* unreachable — a transient outage, never a failure)
|
|
2386
|
+
* AC2). Returns `'unreachable'` when teardown must be retried next tick
|
|
2387
|
+
* (setup info unreachable — a transient outage, never a failure); the caller
|
|
2388
|
+
* journals it through the dedup idiom in its second lock pass (#636), since
|
|
2389
|
+
* this function has no `SchedState` to patch.
|
|
2376
2390
|
*/
|
|
2377
2391
|
function runTeardownFor(deps, issue) {
|
|
2378
2392
|
const info = deps.groundTruth.setupInfo(issue);
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
// #633: AUDITED, NOT DEDUPED. This is a tenth site with #632's shape —
|
|
2382
|
-
// `teardownPendingIssues` reaches it every tick and a `null` return leaves
|
|
2383
|
-
// `cleanup` unset, so an unreachable `setupInfo` re-emits this line once
|
|
2384
|
-
// per reconcile interval for as long as the outage lasts.
|
|
2385
|
-
//
|
|
2386
|
-
// Left as-is deliberately: #632 enumerated nine sites and its plan makes
|
|
2387
|
-
// the boundary load-bearing ("a site outside the table is a NEW issue, not
|
|
2388
|
-
// a reason to widen this one") — widening is what dissolved b-07. The fix
|
|
2389
|
-
// is tracked in #636, and is not a one-liner here: `runTeardownFor` runs
|
|
2390
|
-
// OUTSIDE the store lock and has no `SchedState` to patch, so the marker
|
|
2391
|
-
// has to be threaded through the caller's second lock pass.
|
|
2392
|
-
deps.journal.append((0, journal_1.unitEvent)('ground-truth-unreachable', unit, {
|
|
2393
|
-
detail: 'teardown paused until truth returns',
|
|
2394
|
-
}), deps.now());
|
|
2395
|
-
return null;
|
|
2396
|
-
}
|
|
2393
|
+
if (info === undefined)
|
|
2394
|
+
return 'unreachable';
|
|
2397
2395
|
if (info === null) {
|
|
2398
2396
|
return {
|
|
2399
2397
|
cleanup: 'failed-missing-setup-info',
|
|
@@ -2528,15 +2526,26 @@ function tick(deps, config) {
|
|
|
2528
2526
|
// lock; results land in a second short lock pass together with the report
|
|
2529
2527
|
// dispatch (AC2: teardown, THEN the cheap-tier report agent).
|
|
2530
2528
|
const results = new Map();
|
|
2529
|
+
const unreachable = [];
|
|
2531
2530
|
for (const issue of pass1.teardownPending) {
|
|
2532
2531
|
const teardownResult = runTeardownFor(deps, issue);
|
|
2533
|
-
if (teardownResult
|
|
2532
|
+
if (teardownResult === 'unreachable')
|
|
2533
|
+
unreachable.push(issue);
|
|
2534
|
+
else
|
|
2534
2535
|
results.set(issue, teardownResult);
|
|
2535
2536
|
}
|
|
2536
|
-
if (results.size > 0) {
|
|
2537
|
+
if (results.size > 0 || unreachable.length > 0) {
|
|
2537
2538
|
result = deps.store.withLock((state) => {
|
|
2538
2539
|
const ctx = { deps, config, dispatch, result };
|
|
2539
|
-
|
|
2540
|
+
let next = state;
|
|
2541
|
+
// #636: `setupInfo` answered for these — any unreachable streak is over.
|
|
2542
|
+
for (const issue of results.keys()) {
|
|
2543
|
+
next = clearCondition(next, `issue:${issue}`, 'ground-truth-unreachable', deps.now());
|
|
2544
|
+
}
|
|
2545
|
+
for (const issue of unreachable) {
|
|
2546
|
+
next = journalConditionIfDue(ctx, next, `issue:${issue}`, 'ground-truth-unreachable', 'teardown-paused', { detail: 'teardown paused until truth returns' });
|
|
2547
|
+
}
|
|
2548
|
+
next = recordTeardowns(ctx, next, results);
|
|
2540
2549
|
const withReport = dispatchReportAgents(ctx, next, config);
|
|
2541
2550
|
return { state: withReport, result: ctx.result };
|
|
2542
2551
|
});
|