instar 1.3.586 → 1.3.588

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 (45) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +229 -39
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/IntelligenceRouter.d.ts +10 -0
  5. package/dist/core/IntelligenceRouter.d.ts.map +1 -1
  6. package/dist/core/IntelligenceRouter.js +37 -3
  7. package/dist/core/IntelligenceRouter.js.map +1 -1
  8. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  9. package/dist/core/PostUpdateMigrator.js +17 -0
  10. package/dist/core/PostUpdateMigrator.js.map +1 -1
  11. package/dist/core/WorkEvidence.d.ts +17 -0
  12. package/dist/core/WorkEvidence.d.ts.map +1 -1
  13. package/dist/core/WorkEvidence.js +17 -0
  14. package/dist/core/WorkEvidence.js.map +1 -1
  15. package/dist/core/gapBCommitmentEvidence.d.ts +143 -0
  16. package/dist/core/gapBCommitmentEvidence.d.ts.map +1 -0
  17. package/dist/core/gapBCommitmentEvidence.js +138 -0
  18. package/dist/core/gapBCommitmentEvidence.js.map +1 -0
  19. package/dist/core/internalFrameworkDefault.d.ts +50 -0
  20. package/dist/core/internalFrameworkDefault.d.ts.map +1 -0
  21. package/dist/core/internalFrameworkDefault.js +72 -0
  22. package/dist/core/internalFrameworkDefault.js.map +1 -0
  23. package/dist/core/types.d.ts +39 -0
  24. package/dist/core/types.d.ts.map +1 -1
  25. package/dist/core/types.js.map +1 -1
  26. package/dist/monitoring/CommitmentTracker.d.ts +12 -0
  27. package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
  28. package/dist/monitoring/CommitmentTracker.js +14 -0
  29. package/dist/monitoring/CommitmentTracker.js.map +1 -1
  30. package/dist/monitoring/ReapLog.d.ts +11 -0
  31. package/dist/monitoring/ReapLog.d.ts.map +1 -1
  32. package/dist/monitoring/ReapLog.js +1 -0
  33. package/dist/monitoring/ReapLog.js.map +1 -1
  34. package/dist/monitoring/ResumeQueueDrainer.d.ts +15 -0
  35. package/dist/monitoring/ResumeQueueDrainer.d.ts.map +1 -1
  36. package/dist/monitoring/ResumeQueueDrainer.js +12 -1
  37. package/dist/monitoring/ResumeQueueDrainer.js.map +1 -1
  38. package/dist/scaffold/templates.js +4 -4
  39. package/package.json +1 -1
  40. package/src/data/builtin-manifest.json +19 -19
  41. package/src/scaffold/templates.ts +4 -4
  42. package/upgrades/1.3.587.md +28 -0
  43. package/upgrades/1.3.588.md +27 -0
  44. package/upgrades/side-effects/autonomous-registration-guarantee.md +51 -0
  45. package/upgrades/side-effects/provider-fallback-default-policy.md +52 -0
@@ -35,6 +35,23 @@ export declare const MARKER_WORK_EVIDENCE: readonly ["unverified-under-pressure"
35
35
  * evidence-vocabulary string is here (imported by server.ts + ResumeQueueDrainer.ts).
36
36
  */
37
37
  export declare const AGE_LIMIT_ACTIVE_RUN_REASON = "age-limit (active autonomous run)";
38
+ /**
39
+ * The reap-reason tag for an age-limit recycle whose topic has no per-topic
40
+ * autonomous-run state file (the run was never registered) BUT carries a fresh,
41
+ * qualifying open agent-commitment corroborated by a recent user message
42
+ * (spec: docs/specs/autonomous-registration-guarantee.md, GAP-B Part B). This is
43
+ * the BACKSTOP for an unregistered-but-actively-working autonomous run: the
44
+ * commitment is the independent live-work signal the state-file source cannot see.
45
+ *
46
+ * Parallel to AGE_LIMIT_ACTIVE_RUN_REASON (registered runs) so the drainer can
47
+ * route this candidate to its OWN drain-time liveness re-check
48
+ * (`commitmentStillActiveForTopic`) instead of the state-file read (which is
49
+ * absent here by construction). The reason is the provenance carrier — there is
50
+ * NO new WorkEvidence enum value (the strong `build-or-autonomous-active` signal
51
+ * is reused; the clamped WorkEvidenceName union is untouched). Imported by
52
+ * server.ts (injection) + ResumeQueueDrainer.ts (drain-time routing).
53
+ */
54
+ export declare const COMMITMENT_ACTIVE_RUN_REASON = "age-limit (committed unregistered run)";
38
55
  /**
39
56
  * Closed-world predicate: is this resume-queue PAUSE reason a blunt
40
57
  * emergency/sentinel stop that the drainer may auto-resume once it has gone
@@ -1 +1 @@
1
- {"version":3,"file":"WorkEvidence.d.ts","sourceRoot":"","sources":["../../src/core/WorkEvidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,eAAO,MAAM,oBAAoB,yJAavB,CAAC;AAEX,eAAO,MAAM,kBAAkB,0FAKrB,CAAC;AAEX,eAAO,MAAM,oBAAoB,wCAAyC,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,sCAAsC,CAAC;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAG9F;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AACnE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAY1F;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAYpE;AAED,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE9D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE9E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAI1F"}
1
+ {"version":3,"file":"WorkEvidence.d.ts","sourceRoot":"","sources":["../../src/core/WorkEvidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,eAAO,MAAM,oBAAoB,yJAavB,CAAC;AAEX,eAAO,MAAM,kBAAkB,0FAKrB,CAAC;AAEX,eAAO,MAAM,oBAAoB,wCAAyC,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,sCAAsC,CAAC;AAE/E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,2CAA2C,CAAC;AAErF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mCAAmC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAG9F;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AACnE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAY1F;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAYpE;AAED,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE9D;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE9E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAI1F"}
@@ -53,6 +53,23 @@ export const MARKER_WORK_EVIDENCE = ['unverified-under-pressure'];
53
53
  * evidence-vocabulary string is here (imported by server.ts + ResumeQueueDrainer.ts).
54
54
  */
55
55
  export const AGE_LIMIT_ACTIVE_RUN_REASON = 'age-limit (active autonomous run)';
56
+ /**
57
+ * The reap-reason tag for an age-limit recycle whose topic has no per-topic
58
+ * autonomous-run state file (the run was never registered) BUT carries a fresh,
59
+ * qualifying open agent-commitment corroborated by a recent user message
60
+ * (spec: docs/specs/autonomous-registration-guarantee.md, GAP-B Part B). This is
61
+ * the BACKSTOP for an unregistered-but-actively-working autonomous run: the
62
+ * commitment is the independent live-work signal the state-file source cannot see.
63
+ *
64
+ * Parallel to AGE_LIMIT_ACTIVE_RUN_REASON (registered runs) so the drainer can
65
+ * route this candidate to its OWN drain-time liveness re-check
66
+ * (`commitmentStillActiveForTopic`) instead of the state-file read (which is
67
+ * absent here by construction). The reason is the provenance carrier — there is
68
+ * NO new WorkEvidence enum value (the strong `build-or-autonomous-active` signal
69
+ * is reused; the clamped WorkEvidenceName union is untouched). Imported by
70
+ * server.ts (injection) + ResumeQueueDrainer.ts (drain-time routing).
71
+ */
72
+ export const COMMITMENT_ACTIVE_RUN_REASON = 'age-limit (committed unregistered run)';
56
73
  /**
57
74
  * Closed-world predicate: is this resume-queue PAUSE reason a blunt
58
75
  * emergency/sentinel stop that the drainer may auto-resume once it has gone
@@ -1 +1 @@
1
- {"version":3,"file":"WorkEvidence.js","sourceRoot":"","sources":["../../src/core/WorkEvidence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WorkEvidence.js","sourceRoot":"","sources":["../../src/core/WorkEvidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * GAP-B commitment-evidence backstop — the pure qualifying + agreement predicate.
3
+ *
4
+ * Spec: docs/specs/autonomous-registration-guarantee.md (Part B + Frontloaded
5
+ * Decisions D1/D2/D7/D8).
6
+ *
7
+ * The reaper revives a REGISTERED autonomous run from its per-topic state file.
8
+ * An UNregistered-but-actively-working run (operator said "go autonomous" but the
9
+ * skill never wrote the state file) has no state file → today it dies at the
10
+ * age-limit reap. This module is the BACKSTOP: it recognizes an independent
11
+ * live-work signal — a FRESH open agent-commitment for the topic, CORROBORATED by
12
+ * a recent user message — and (when armed, dark by default) lets the existing
13
+ * revival machinery keep the run alive.
14
+ *
15
+ * This file holds ONLY the deterministic predicates (D1 freshness, D2 qualifying
16
+ * set, D8 agreement). The wiring (the dark-gate, the injection, the Part A
17
+ * surface, the drain-time re-check) lives at the server callsite. Extracting the
18
+ * predicate here makes D1/D2/D7/D8 unit-testable against a REAL CommitmentTracker
19
+ * with no server boot — and guarantees the enqueue-time check and the drain-time
20
+ * re-check (D9) compute the IDENTICAL verdict (they call this same function), so
21
+ * they can never disagree.
22
+ *
23
+ * Signal vs Authority: this returns a boolean SIGNAL. The authority that decides
24
+ * revival remains the unchanged `evidenceEligible`/drainer. No new WorkEvidence
25
+ * enum value; provenance rides the reason tag + the reap-log `evidenceSource`.
26
+ */
27
+ import type { Commitment } from '../monitoring/CommitmentTracker.js';
28
+ /**
29
+ * Part D (spec: autonomous-registration-guarantee.md) — the pure inbound-user-
30
+ * message recency predicate over a topic's message-history tail. Extracted here
31
+ * so it is unit-testable against real TelegramAdapter.getTopicHistory output
32
+ * WITHOUT a server boot, and shared by every `recentUserMessage` consumer (the
33
+ * ReapGuard/SessionReaper deps AND the GAP-B D8 agreement check) so KEEP and
34
+ * eligibility compute the identical truth.
35
+ *
36
+ * An inbound USER message = `fromUser === true` (NOT an agent/system echo).
37
+ * Freshness = its `timestamp` within `withinMs`. History is oldest→newest, so the
38
+ * newest user entry (the first hit scanning backwards) is the verdict. A
39
+ * non-parseable timestamp is skipped (never a false positive). Returns false on
40
+ * an empty / user-message-free history. Pure — the server callsite wraps the
41
+ * getTopicHistory call in its own try/catch (D7 fail-open).
42
+ */
43
+ export interface RecencyLogEntry {
44
+ fromUser: boolean;
45
+ timestamp: string;
46
+ }
47
+ export declare function recentUserMessageFromHistory(history: readonly RecencyLogEntry[], withinMs: number, now?: number): boolean;
48
+ /** The minimal slice of CommitmentTracker this predicate reads. */
49
+ export interface GapBCommitmentSource {
50
+ /** Active commitments bound to a topic (pending/verified/violated, not expired). */
51
+ getActiveByTopicId(topicId: number): Commitment[];
52
+ }
53
+ export interface GapBQualifyDeps {
54
+ /** This machine's mesh identity, for the D2 local-origin filter. May be absent
55
+ * (single-machine / pre-mesh) — then no commitment is excluded on origin. */
56
+ ownMachineId?: string;
57
+ /** D1 freshness horizon on `createdAt` (ms). */
58
+ freshCommitmentWindowMs: number;
59
+ /** D8 agreement window — the SAME `recentUserMessage(topic, window)` predicate
60
+ * ReapGuard's commitment KEEP uses (the staleCommitmentWindowMs / 8h horizon). */
61
+ staleCommitmentWindowMs: number;
62
+ /** D8 corroboration: a recent INBOUND USER message on the topic within window.
63
+ * Shared with ReapGuard's dep so KEEP and eligibility cannot disagree. */
64
+ recentUserMessage: (topicId: number, withinMs: number) => boolean;
65
+ /** Wall clock (injected for testability). Default Date.now. */
66
+ now?: () => number;
67
+ }
68
+ /**
69
+ * D2 qualifying-commitment predicate (the per-commitment half).
70
+ *
71
+ * A commitment counts as live-work evidence only if ALL hold:
72
+ * - `status === 'pending'` (NOT verified/violated — a violated commitment is a
73
+ * FAILING session, not a working one);
74
+ * - agent-driven: `owner === 'agent'` (default), OR `owner === 'user'` with
75
+ * `blockedOn` ∈ {none, undefined} — a commitment WAITING on the user
76
+ * (`blockedOn` ∈ {user-input, user-authorization}) is the opposite of an
77
+ * active autonomous run and is excluded;
78
+ * - not beacon-paused and not beacon-suppressed;
79
+ * - local-origin: `originMachineId` is this machine or absent (a replicated peer
80
+ * commitment is advisory data, never revival authority);
81
+ * - D1 freshness: `createdAt` within `freshCommitmentWindowMs` — `createdAt` ONLY
82
+ * (no `updatedAt` exists; bookkeeping/beacon timestamps must NOT refresh
83
+ * freshness — a 3-day promise a beacon pinged 5min ago is not a live session).
84
+ */
85
+ export declare function commitmentQualifies(c: Commitment, deps: Pick<GapBQualifyDeps, 'ownMachineId' | 'freshCommitmentWindowMs' | 'now'>): boolean;
86
+ /**
87
+ * The full GAP-B eligibility verdict for a topic (D1/D2 + D8 agreement).
88
+ *
89
+ * True iff (a) at least one qualifying commitment exists for the topic (D1/D2),
90
+ * AND (b) there is a recent user message within the stale-commitment window (D8 —
91
+ * the SAME corroboration ReapGuard's commitment KEEP uses, so KEEP and
92
+ * eligibility AGREE; without this the 2026-06-13 13-session reap/revive loop
93
+ * returns). Fail-open (D7): any read throwing ⇒ false (no injection), never a
94
+ * spurious eligibility.
95
+ */
96
+ export declare function gapBEligibleForTopic(topicId: number, source: GapBCommitmentSource, deps: GapBQualifyDeps): boolean;
97
+ /** Dark-gate posture for the Part B injection (D5), resolved from config. */
98
+ export interface GapBInjectionGate {
99
+ /** True only when `monitoring.resumeQueue.commitmentEvidence.enabled === true`.
100
+ * Omitted ⇒ OFF on BOTH fleet AND dev (the containment). */
101
+ armed: boolean;
102
+ /** dryRun defaults TRUE when armed: logs "would inject" without tagging the
103
+ * candidate (the dark soak proving KEEP/eligibility agree before evidence
104
+ * flows). Only `armed && !dryRun` actually injects. */
105
+ dryRun: boolean;
106
+ }
107
+ /**
108
+ * Resolve the Part B dark-gate from the resumeQueue config block (D5).
109
+ * `enabled` MUST be an explicit `true` — absence/false ⇒ disarmed (no injection
110
+ * on fleet OR dev). `dryRun` defaults true when armed.
111
+ */
112
+ export declare function resolveGapBInjectionGate(cfg?: {
113
+ enabled?: boolean;
114
+ dryRun?: boolean;
115
+ }): GapBInjectionGate;
116
+ /** The full reaped-session decision: did GAP-B evidence fire, and does it INJECT? */
117
+ export interface GapBInjectionDecision {
118
+ /** The qualifying-commitment + D8 verdict fired (drives the Part A surface,
119
+ * even in dryRun — the surface exists to make the unregistered run visible). */
120
+ fired: boolean;
121
+ /** The LIVE injection switch: `fired && armed && !dryRun`. Only this tags the
122
+ * candidate + the reap-log. dryRun logs the verdict but injects nothing. */
123
+ inject: boolean;
124
+ }
125
+ /**
126
+ * Compute the reaped-session GAP-B decision. Pinned to the SAME branch the
127
+ * state-file source uses: an `age-limit` reap whose per-topic state file is
128
+ * ABSENT (`stateFilePresent === false` — a registered run is handled upstream by
129
+ * AGE_LIMIT_ACTIVE_RUN_REASON). When disarmed, returns a strict no-op
130
+ * `{fired:false, inject:false}` (the dark-default containment: no injection ⇒ no
131
+ * revival ⇒ the 2026-06-13 loop is structurally impossible while dark).
132
+ *
133
+ * `eligible` is the precomputed `gapBEligibleForTopic` verdict (kept a parameter
134
+ * so the caller can short-circuit the cost when disarmed, and so this stays a
135
+ * pure decision function over booleans).
136
+ */
137
+ export declare function decideGapBInjection(input: {
138
+ gate: GapBInjectionGate;
139
+ reason: string;
140
+ stateFilePresent: boolean;
141
+ eligible: boolean;
142
+ }): GapBInjectionDecision;
143
+ //# sourceMappingURL=gapBCommitmentEvidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gapBCommitmentEvidence.d.ts","sourceRoot":"","sources":["../../src/core/gapBCommitmentEvidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAErE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAYT;AAED,mEAAmE;AACnE,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,eAAe;IAC9B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,uBAAuB,EAAE,MAAM,CAAC;IAChC;uFACmF;IACnF,uBAAuB,EAAE,MAAM,CAAC;IAChC;+EAC2E;IAC3E,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAClE,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,UAAU,EACb,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,cAAc,GAAG,yBAAyB,GAAG,KAAK,CAAC,GAC9E,OAAO,CAgBT;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,eAAe,GACpB,OAAO,CAcT;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC;iEAC6D;IAC7D,KAAK,EAAE,OAAO,CAAC;IACf;;4DAEwD;IACxD,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,CAAC,EAAE;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,iBAAiB,CAGpB;AAED,qFAAqF;AACrF,MAAM,WAAW,qBAAqB;IACpC;qFACiF;IACjF,KAAK,EAAE,OAAO,CAAC;IACf;iFAC6E;IAC7E,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,qBAAqB,CAMxB"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * GAP-B commitment-evidence backstop — the pure qualifying + agreement predicate.
3
+ *
4
+ * Spec: docs/specs/autonomous-registration-guarantee.md (Part B + Frontloaded
5
+ * Decisions D1/D2/D7/D8).
6
+ *
7
+ * The reaper revives a REGISTERED autonomous run from its per-topic state file.
8
+ * An UNregistered-but-actively-working run (operator said "go autonomous" but the
9
+ * skill never wrote the state file) has no state file → today it dies at the
10
+ * age-limit reap. This module is the BACKSTOP: it recognizes an independent
11
+ * live-work signal — a FRESH open agent-commitment for the topic, CORROBORATED by
12
+ * a recent user message — and (when armed, dark by default) lets the existing
13
+ * revival machinery keep the run alive.
14
+ *
15
+ * This file holds ONLY the deterministic predicates (D1 freshness, D2 qualifying
16
+ * set, D8 agreement). The wiring (the dark-gate, the injection, the Part A
17
+ * surface, the drain-time re-check) lives at the server callsite. Extracting the
18
+ * predicate here makes D1/D2/D7/D8 unit-testable against a REAL CommitmentTracker
19
+ * with no server boot — and guarantees the enqueue-time check and the drain-time
20
+ * re-check (D9) compute the IDENTICAL verdict (they call this same function), so
21
+ * they can never disagree.
22
+ *
23
+ * Signal vs Authority: this returns a boolean SIGNAL. The authority that decides
24
+ * revival remains the unchanged `evidenceEligible`/drainer. No new WorkEvidence
25
+ * enum value; provenance rides the reason tag + the reap-log `evidenceSource`.
26
+ */
27
+ export function recentUserMessageFromHistory(history, withinMs, now = Date.now()) {
28
+ const cutoff = now - withinMs;
29
+ for (let i = history.length - 1; i >= 0; i--) {
30
+ const entry = history[i];
31
+ if (!entry.fromUser)
32
+ continue; // skip agent/system echoes
33
+ const ts = Date.parse(entry.timestamp);
34
+ if (!Number.isFinite(ts))
35
+ continue;
36
+ // The first USER entry scanning backwards is the NEWEST user message — its
37
+ // recency is the verdict (every earlier user entry is older).
38
+ return ts >= cutoff;
39
+ }
40
+ return false;
41
+ }
42
+ /**
43
+ * D2 qualifying-commitment predicate (the per-commitment half).
44
+ *
45
+ * A commitment counts as live-work evidence only if ALL hold:
46
+ * - `status === 'pending'` (NOT verified/violated — a violated commitment is a
47
+ * FAILING session, not a working one);
48
+ * - agent-driven: `owner === 'agent'` (default), OR `owner === 'user'` with
49
+ * `blockedOn` ∈ {none, undefined} — a commitment WAITING on the user
50
+ * (`blockedOn` ∈ {user-input, user-authorization}) is the opposite of an
51
+ * active autonomous run and is excluded;
52
+ * - not beacon-paused and not beacon-suppressed;
53
+ * - local-origin: `originMachineId` is this machine or absent (a replicated peer
54
+ * commitment is advisory data, never revival authority);
55
+ * - D1 freshness: `createdAt` within `freshCommitmentWindowMs` — `createdAt` ONLY
56
+ * (no `updatedAt` exists; bookkeeping/beacon timestamps must NOT refresh
57
+ * freshness — a 3-day promise a beacon pinged 5min ago is not a live session).
58
+ */
59
+ export function commitmentQualifies(c, deps) {
60
+ if (c.status !== 'pending')
61
+ return false;
62
+ const owner = c.owner ?? 'agent';
63
+ const blockedOn = c.blockedOn ?? 'none';
64
+ const agentDriven = owner === 'agent' || (owner === 'user' && blockedOn === 'none');
65
+ if (!agentDriven)
66
+ return false;
67
+ if (c.beaconPaused || c.beaconSuppressed)
68
+ return false;
69
+ if (c.originMachineId && deps.ownMachineId && c.originMachineId !== deps.ownMachineId) {
70
+ return false;
71
+ }
72
+ const nowMs = (deps.now ?? Date.now)();
73
+ const createdMs = Date.parse(c.createdAt);
74
+ if (!Number.isFinite(createdMs) || createdMs < nowMs - deps.freshCommitmentWindowMs) {
75
+ return false;
76
+ }
77
+ return true;
78
+ }
79
+ /**
80
+ * The full GAP-B eligibility verdict for a topic (D1/D2 + D8 agreement).
81
+ *
82
+ * True iff (a) at least one qualifying commitment exists for the topic (D1/D2),
83
+ * AND (b) there is a recent user message within the stale-commitment window (D8 —
84
+ * the SAME corroboration ReapGuard's commitment KEEP uses, so KEEP and
85
+ * eligibility AGREE; without this the 2026-06-13 13-session reap/revive loop
86
+ * returns). Fail-open (D7): any read throwing ⇒ false (no injection), never a
87
+ * spurious eligibility.
88
+ */
89
+ export function gapBEligibleForTopic(topicId, source, deps) {
90
+ try {
91
+ const qualifies = source
92
+ .getActiveByTopicId(topicId)
93
+ .some((c) => commitmentQualifies(c, deps));
94
+ if (!qualifies)
95
+ return false;
96
+ // D8 AGREEMENT — non-negotiable. A commitment that would NOT keep the session
97
+ // alive (no recent user message) cannot revive it either.
98
+ return deps.recentUserMessage(topicId, deps.staleCommitmentWindowMs);
99
+ }
100
+ catch {
101
+ // @silent-fallback-ok — D7: a throwing tracker/predicate contributes NOTHING;
102
+ // the reap proceeds exactly as today (no injection, no revive).
103
+ return false;
104
+ }
105
+ }
106
+ /**
107
+ * Resolve the Part B dark-gate from the resumeQueue config block (D5).
108
+ * `enabled` MUST be an explicit `true` — absence/false ⇒ disarmed (no injection
109
+ * on fleet OR dev). `dryRun` defaults true when armed.
110
+ */
111
+ export function resolveGapBInjectionGate(cfg) {
112
+ const armed = cfg?.enabled === true;
113
+ return { armed, dryRun: cfg?.dryRun !== false };
114
+ }
115
+ /**
116
+ * Compute the reaped-session GAP-B decision. Pinned to the SAME branch the
117
+ * state-file source uses: an `age-limit` reap whose per-topic state file is
118
+ * ABSENT (`stateFilePresent === false` — a registered run is handled upstream by
119
+ * AGE_LIMIT_ACTIVE_RUN_REASON). When disarmed, returns a strict no-op
120
+ * `{fired:false, inject:false}` (the dark-default containment: no injection ⇒ no
121
+ * revival ⇒ the 2026-06-13 loop is structurally impossible while dark).
122
+ *
123
+ * `eligible` is the precomputed `gapBEligibleForTopic` verdict (kept a parameter
124
+ * so the caller can short-circuit the cost when disarmed, and so this stays a
125
+ * pure decision function over booleans).
126
+ */
127
+ export function decideGapBInjection(input) {
128
+ if (!input.gate.armed)
129
+ return { fired: false, inject: false };
130
+ if (input.reason !== 'age-limit')
131
+ return { fired: false, inject: false };
132
+ if (input.stateFilePresent)
133
+ return { fired: false, inject: false };
134
+ if (!input.eligible)
135
+ return { fired: false, inject: false };
136
+ return { fired: true, inject: !input.gate.dryRun };
137
+ }
138
+ //# sourceMappingURL=gapBCommitmentEvidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gapBCommitmentEvidence.js","sourceRoot":"","sources":["../../src/core/gapBCommitmentEvidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * internalFrameworkDefault — the PROVIDER-FALLBACK DEFAULT POLICY
3
+ * (docs/specs/provider-fallback-default-policy.md §4.1–4.2).
4
+ *
5
+ * Computes the effective `ComponentFrameworksConfig` that turns the already-shipped
6
+ * IntelligenceRouter failure-swap engine ON out-of-the-box: internal, lightweight,
7
+ * high-frequency categories (sentinel / gate / reflector) run on the FIRST ACTIVE
8
+ * framework in a documented preference chain, with the remaining active frameworks
9
+ * as the ordered `failureSwap` tail and Claude as the last resort.
10
+ *
11
+ * This is a PURE policy resolver — it does NOT probe the system. The caller passes
12
+ * the already-computed active-framework set (probed once at boot via the router's
13
+ * own `buildProvider(fw) !== null` truth — §4.2), so this module is unit-testable
14
+ * in isolation.
15
+ *
16
+ * What it does NOT do (deliberate, per §4.1):
17
+ * - `job` is EXCLUDED — routing cost-bearing background jobs (e.g. CartographerSweep)
18
+ * off Claude by default would silently auto-arm them; an operator arms `categories.job`.
19
+ * - `other` is left on the agent default (unchanged).
20
+ * - Spawned interactive sessions stay on `topicFrameworks` (out of scope).
21
+ */
22
+ import type { IntelligenceFramework } from './intelligenceProviderFactory.js';
23
+ import type { ComponentFrameworksConfig } from './IntelligenceRouter.js';
24
+ /**
25
+ * The internal-component provider preference chain (§4.1 / §6.5). ONE named,
26
+ * documented, inspectable place. Order: Codex first (operator directive), Claude
27
+ * last (the true last resort for background work). A unit test validates every
28
+ * entry against the real `IntelligenceFramework` enum so an unknown name never ships.
29
+ */
30
+ export declare const INTERNAL_FRAMEWORK_PREFERENCE: readonly IntelligenceFramework[];
31
+ /**
32
+ * Compute the default `componentFrameworks` from the active-framework set.
33
+ *
34
+ * @param activeFrameworks the preference chain filtered to frameworks ACTIVE in this
35
+ * agent, IN PREFERENCE ORDER (the caller filters `INTERNAL_FRAMEWORK_PREFERENCE`
36
+ * by `buildProvider(fw) !== null`). MUST already be ordered + de-duplicated.
37
+ * @returns the effective `ComponentFrameworksConfig`:
38
+ * - `categories.{sentinel,gate,reflector}` = `active[0]` (first active off-Claude,
39
+ * or claude-code if that's all that's active)
40
+ * - `failureSwap` = `active.slice(1)` (the ordered tail, claude-code last)
41
+ * - `fallback: 'default'`
42
+ *
43
+ * No-op cases (byte-identical to today — primary is the agent default, empty swap):
44
+ * - `active === []` → `{ failureSwap: [], fallback: 'default' }`
45
+ * - `active === ['claude-code']` → `{ failureSwap: [], fallback: 'default' }`
46
+ * (claude-code IS the default framework, so emitting it as the primary category
47
+ * value is harmless, but we leave categories unset to keep the no-op truly inert)
48
+ */
49
+ export declare function resolveInternalFrameworkDefault(activeFrameworks: readonly IntelligenceFramework[]): ComponentFrameworksConfig;
50
+ //# sourceMappingURL=internalFrameworkDefault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internalFrameworkDefault.d.ts","sourceRoot":"","sources":["../../src/core/internalFrameworkDefault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EAAE,SAAS,qBAAqB,EAKhE,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,+BAA+B,CAC7C,gBAAgB,EAAE,SAAS,qBAAqB,EAAE,GACjD,yBAAyB,CAqB3B"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * internalFrameworkDefault — the PROVIDER-FALLBACK DEFAULT POLICY
3
+ * (docs/specs/provider-fallback-default-policy.md §4.1–4.2).
4
+ *
5
+ * Computes the effective `ComponentFrameworksConfig` that turns the already-shipped
6
+ * IntelligenceRouter failure-swap engine ON out-of-the-box: internal, lightweight,
7
+ * high-frequency categories (sentinel / gate / reflector) run on the FIRST ACTIVE
8
+ * framework in a documented preference chain, with the remaining active frameworks
9
+ * as the ordered `failureSwap` tail and Claude as the last resort.
10
+ *
11
+ * This is a PURE policy resolver — it does NOT probe the system. The caller passes
12
+ * the already-computed active-framework set (probed once at boot via the router's
13
+ * own `buildProvider(fw) !== null` truth — §4.2), so this module is unit-testable
14
+ * in isolation.
15
+ *
16
+ * What it does NOT do (deliberate, per §4.1):
17
+ * - `job` is EXCLUDED — routing cost-bearing background jobs (e.g. CartographerSweep)
18
+ * off Claude by default would silently auto-arm them; an operator arms `categories.job`.
19
+ * - `other` is left on the agent default (unchanged).
20
+ * - Spawned interactive sessions stay on `topicFrameworks` (out of scope).
21
+ */
22
+ /**
23
+ * The internal-component provider preference chain (§4.1 / §6.5). ONE named,
24
+ * documented, inspectable place. Order: Codex first (operator directive), Claude
25
+ * last (the true last resort for background work). A unit test validates every
26
+ * entry against the real `IntelligenceFramework` enum so an unknown name never ships.
27
+ */
28
+ export const INTERNAL_FRAMEWORK_PREFERENCE = [
29
+ 'codex-cli',
30
+ 'pi-cli',
31
+ 'gemini-cli',
32
+ 'claude-code',
33
+ ];
34
+ /**
35
+ * Compute the default `componentFrameworks` from the active-framework set.
36
+ *
37
+ * @param activeFrameworks the preference chain filtered to frameworks ACTIVE in this
38
+ * agent, IN PREFERENCE ORDER (the caller filters `INTERNAL_FRAMEWORK_PREFERENCE`
39
+ * by `buildProvider(fw) !== null`). MUST already be ordered + de-duplicated.
40
+ * @returns the effective `ComponentFrameworksConfig`:
41
+ * - `categories.{sentinel,gate,reflector}` = `active[0]` (first active off-Claude,
42
+ * or claude-code if that's all that's active)
43
+ * - `failureSwap` = `active.slice(1)` (the ordered tail, claude-code last)
44
+ * - `fallback: 'default'`
45
+ *
46
+ * No-op cases (byte-identical to today — primary is the agent default, empty swap):
47
+ * - `active === []` → `{ failureSwap: [], fallback: 'default' }`
48
+ * - `active === ['claude-code']` → `{ failureSwap: [], fallback: 'default' }`
49
+ * (claude-code IS the default framework, so emitting it as the primary category
50
+ * value is harmless, but we leave categories unset to keep the no-op truly inert)
51
+ */
52
+ export function resolveInternalFrameworkDefault(activeFrameworks) {
53
+ const active = activeFrameworks;
54
+ // No off-Claude provider active ⇒ a true no-op: no category routing, empty swap.
55
+ // 'claude-code' alone means there is nothing to route OFF Claude onto, so the
56
+ // policy is inert (matches §4.2 — never made worse, never spammed with degrades).
57
+ if (active.length === 0 || (active.length === 1 && active[0] === 'claude-code')) {
58
+ return { failureSwap: [], fallback: 'default' };
59
+ }
60
+ const primary = active[0];
61
+ return {
62
+ categories: {
63
+ sentinel: primary,
64
+ gate: primary,
65
+ reflector: primary,
66
+ // `job` and `other` are deliberately ABSENT (§4.1).
67
+ },
68
+ failureSwap: active.slice(1),
69
+ fallback: 'default',
70
+ };
71
+ }
72
+ //# sourceMappingURL=internalFrameworkDefault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internalFrameworkDefault.js","sourceRoot":"","sources":["../../src/core/internalFrameworkDefault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAqC;IAC7E,WAAW;IACX,QAAQ;IACR,YAAY;IACZ,aAAa;CACL,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,+BAA+B,CAC7C,gBAAkD;IAElD,MAAM,MAAM,GAAG,gBAAgB,CAAC;IAEhC,iFAAiF;IACjF,8EAA8E;IAC9E,kFAAkF;IAClF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,EAAE,CAAC;QAChF,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAClD,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO;QACL,UAAU,EAAE;YACV,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,OAAO;YAClB,oDAAoD;SACrD;QACD,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5B,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC"}
@@ -228,6 +228,14 @@ export interface SessionManagerConfig {
228
228
  categories?: Partial<Record<'sentinel' | 'gate' | 'job' | 'reflector' | 'other', 'claude-code' | 'codex-cli' | 'gemini-cli' | 'pi-cli'>>;
229
229
  overrides?: Record<string, 'claude-code' | 'codex-cli' | 'gemini-cli' | 'pi-cli'>;
230
230
  fallback?: 'default' | 'none';
231
+ /**
232
+ * Ordered fallback frameworks a SAFETY-GATING call tries when its primary
233
+ * provider fails at runtime, before failing closed (provider-fallback-default-policy.md).
234
+ * The provider-fallback DEFAULT POLICY computes this automatically from the active
235
+ * set (sentinel/gate/reflector → first active off-Claude, remaining active as the
236
+ * tail) when this whole block is unset; an operator who sets the block supplies it.
237
+ */
238
+ failureSwap?: Array<'claude-code' | 'codex-cli' | 'gemini-cli' | 'pi-cli'>;
231
239
  };
232
240
  /**
233
241
  * The agent's resolved runtime framework — the single source of
@@ -2676,6 +2684,16 @@ export interface InstarConfig {
2676
2684
  */
2677
2685
  openMs?: number;
2678
2686
  };
2687
+ /**
2688
+ * Per-attempt swap timeout (ms) for the IntelligenceRouter failure-swap loop
2689
+ * (docs/specs/provider-fallback-default-policy.md §4.5). Each gating swap attempt
2690
+ * races this cap; a slow-but-not-erroring provider is abandoned at the cap and the
2691
+ * loop advances to the next target. INLINE-DEFAULTED to 5000ms at the router
2692
+ * construction site — absent ⇒ 5s applies; present ⇒ the operator's value wins.
2693
+ * Deliberately kept out of ConfigDefaults/migrateConfig (codexExecJson precedent)
2694
+ * so absence is the default state, never a persisted block.
2695
+ */
2696
+ swapAttemptTimeoutMs?: number;
2679
2697
  /**
2680
2698
  * Anthropic subscription-path routing for INTERNAL intelligence calls
2681
2699
  * (sentinels, gates, extractors) — the June-15 readiness lever
@@ -4146,6 +4164,27 @@ export interface MonitoringConfig {
4146
4164
  * ConfigDefaults — preserves the fleet flip).
4147
4165
  */
4148
4166
  autoHealStaleHostLock?: boolean;
4167
+ /**
4168
+ * GAP-B commitment-evidence backstop (spec:
4169
+ * autonomous-registration-guarantee.md, Part B). When an age-limit reap hits
4170
+ * a topic with NO per-topic autonomous-run state file but a FRESH qualifying
4171
+ * open agent-commitment corroborated by a recent user message (D8), inject
4172
+ * `build-or-autonomous-active` so an UNregistered-but-working run survives.
4173
+ *
4174
+ * Ships DARK (the containment): `enabled` is OMITTED so the injection is OFF
4175
+ * on BOTH fleet AND dev by default — no injection ⇒ no revival ⇒ the
4176
+ * 2026-06-13 loop is structurally impossible while dark. Set `enabled:true`
4177
+ * to arm; `dryRun:true` (the default when armed) logs "would inject" without
4178
+ * tagging the candidate, so a dark-soak can confirm KEEP/eligibility agree on
4179
+ * real data BEFORE evidence actually flows. CODE-defaulted (absent from
4180
+ * ConfigDefaults — the resumeQueue.* dark-default discipline, no migration).
4181
+ */
4182
+ commitmentEvidence?: {
4183
+ enabled?: boolean;
4184
+ dryRun?: boolean;
4185
+ /** Freshness horizon on `createdAt` (D1). Default 6h. */
4186
+ freshCommitmentWindowMs?: number;
4187
+ };
4149
4188
  };
4150
4189
  /**
4151
4190
  * AgentWorktreeReaper (Responsible Resource Usage — OS resource hygiene).