opencode-swarm 7.159.2 → 7.160.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background/delegation-health.d.ts +1 -1
- package/dist/cli/{coder-settlement-hny3vh3e.js → coder-settlement-zn552sp9.js} +11 -10
- package/dist/cli/{config-doctor-00ex0s3k.js → config-doctor-ddtdz2g0.js} +3 -3
- package/dist/cli/{core-03tedwzg.js → core-embasn2j.js} +2 -2
- package/dist/cli/{curation-policy-z0a5akng.js → curation-policy-agr6ga1s.js} +6 -6
- package/dist/cli/{curator-n81nzdw8.js → curator-dgp6dxxn.js} +32 -31
- package/dist/cli/curator-llm-factory-7cwvmc46.js +67 -0
- package/dist/cli/{evidence-summary-service-nz7y1w2a.js → evidence-summary-service-sbnyann4.js} +14 -13
- package/dist/cli/{gate-evidence-dxafmzrn.js → gate-evidence-5v67a1dz.js} +7 -7
- package/dist/cli/guardrail-explain-2gwarnca.js +68 -0
- package/dist/cli/{guardrail-log-t8c7acxg.js → guardrail-log-zbnbff1y.js} +9 -6
- package/dist/cli/{guardrail-reset-0ft2gf03.js → guardrail-reset-3cnz54hx.js} +32 -31
- package/dist/cli/{hive-promoter-brq9cx7c.js → hive-promoter-7cr7t2kg.js} +32 -31
- package/dist/cli/{index-1xcve0gc.js → index-1f4n43yz.js} +2 -2
- package/dist/cli/{index-b5s1n149.js → index-3055dgzp.js} +7 -7
- package/dist/cli/{index-bmst1sje.js → index-3yh737hc.js} +6 -6
- package/dist/cli/{index-0zerbq1v.js → index-4mm22fzj.js} +23 -14
- package/dist/cli/{index-qypnqmcj.js → index-5m7qjj29.js} +24 -7
- package/dist/cli/{index-rq461prn.js → index-7qv869f0.js} +6 -6
- package/dist/cli/{index-ky2r092m.js → index-85qjc7b2.js} +2 -2
- package/dist/cli/{index-y55hqgcj.js → index-8bjv01t8.js} +4 -4
- package/dist/cli/{index-dgt8z19x.js → index-962jgzdq.js} +1 -1
- package/dist/cli/{index-vq4d1h7t.js → index-9fspg1xw.js} +1 -1
- package/dist/cli/{index-7tjamatf.js → index-9k3zc2t8.js} +7 -7
- package/dist/cli/{index-p2m1skjz.js → index-9q6w7kke.js} +1 -1
- package/dist/cli/{index-av3gnekk.js → index-b5adxpy6.js} +1 -1
- package/dist/cli/{index-w1rhyqw2.js → index-cn233hsy.js} +1 -1
- package/dist/cli/{index-mcan50mx.js → index-d9s5hb0m.js} +4 -4
- package/dist/cli/{index-prknc0xn.js → index-dke4wzkn.js} +108 -44
- package/dist/cli/index-e75bzfgd.js +785 -0
- package/dist/cli/{index-8gh97gkz.js → index-fzkx24q5.js} +2 -2
- package/dist/cli/{index-m0gfzxw1.js → index-gt8cxfbp.js} +2 -2
- package/dist/cli/{index-yt75r1er.js → index-h3re5c78.js} +1 -1
- package/dist/cli/{index-k7kvrwbj.js → index-jmths6jj.js} +34 -33
- package/dist/cli/{index-8ahjx7vt.js → index-kkfgygvn.js} +4 -4
- package/dist/cli/{index-q8yma345.js → index-p39xem8b.js} +5 -5
- package/dist/cli/{index-e1jcdpdg.js → index-py6bqwnb.js} +2 -2
- package/dist/cli/{index-6sheh3yp.js → index-q6gjwy7m.js} +19 -10
- package/dist/cli/{index-200myvdx.js → index-rhc8jve7.js} +2 -2
- package/dist/cli/{index-9ev0bbqh.js → index-rnyt2z5r.js} +346 -98
- package/dist/cli/{index-1e9rzhmr.js → index-rq7k03rk.js} +4 -4
- package/dist/cli/{index-egc8d995.js → index-s7w428r3.js} +1 -1
- package/dist/cli/{index-caqjwnak.js → index-sy5aeegg.js} +11 -2
- package/dist/cli/{index-b2dh37cf.js → index-va1edd2n.js} +5 -5
- package/dist/cli/{index-eh1gh043.js → index-w699ekk9.js} +4 -4
- package/dist/cli/{index-nmp47dmm.js → index-wzx6atbv.js} +13 -4
- package/dist/cli/{index-jd7mz4yg.js → index-xs15netk.js} +1 -1
- package/dist/cli/{index-wzc6vzq6.js → index-yrar1ask.js} +3 -3
- package/dist/cli/{index-v7wm4mw8.js → index-zjvf7edj.js} +3 -3
- package/dist/cli/index.js +32 -31
- package/dist/cli/{knowledge-escalator-rxagfxnk.js → knowledge-escalator-zksm9833.js} +13 -12
- package/dist/cli/{knowledge-events-ymwdv799.js → knowledge-events-ayta750w.js} +11 -10
- package/dist/cli/{knowledge-link-n1825n09.js → knowledge-link-7c7fjnzc.js} +5 -5
- package/dist/cli/{knowledge-store-nxm4xvvq.js → knowledge-store-q5axge8b.js} +6 -6
- package/dist/cli/{knowledge-validator-gtmq35k8.js → knowledge-validator-3rrbva2p.js} +8 -8
- package/dist/cli/{model-preflight-w85ecyxh.js → model-preflight-x9szw1v4.js} +1 -1
- package/dist/cli/{pending-delegations-zdgazhdf.js → pending-delegations-kc7tzxg9.js} +5 -3
- package/dist/cli/{pr-review-reentry-authorization-jgzb0pma.js → pr-review-reentry-authorization-vag5gh50.js} +32 -31
- package/dist/cli/{pr-subscriptions-pxv24d5k.js → pr-subscriptions-wbdw9a82.js} +5 -4
- package/dist/cli/{runner-fzgkhx6a.js → runner-p9wg6z34.js} +6 -6
- package/dist/cli/{scan-cursor-fasdj7kj.js → scan-cursor-4fjwtt1k.js} +7 -7
- package/dist/cli/{schema-3x28z3rp.js → schema-d0nbzj5k.js} +2 -2
- package/dist/cli/{scope-persistence-p8dnxfhx.js → scope-persistence-bckcbc8h.js} +10 -9
- package/dist/cli/{skill-generator-6tjyffgd.js → skill-generator-kebhevet.js} +15 -14
- package/dist/cli/{telemetry-3rh94wv3.js → telemetry-gpr9s3sm.js} +3 -1
- package/dist/cli/{worktree-collision-ownership-3bbn1n2r.js → worktree-collision-ownership-h8qswnrp.js} +6 -5
- package/dist/cli/{worktree-isolation-1470tnxc.js → worktree-isolation-q0kbmadz.js} +32 -31
- package/dist/config/context-window.d.ts +11 -4
- package/dist/config/evidence-schema.d.ts +6 -6
- package/dist/context-map/telemetry.d.ts +1 -1
- package/dist/health/learning-health.d.ts +356 -0
- package/dist/hooks/context-budget.d.ts +10 -1
- package/dist/hooks/curator.d.ts +2 -0
- package/dist/hooks/final-context-accounting.d.ts +2 -0
- package/dist/hooks/model-limits.d.ts +56 -25
- package/dist/hooks/skill-usage-pending.d.ts +1 -1
- package/dist/index.js +588 -587
- package/dist/observability/catalog.d.ts +2 -2
- package/dist/observability/ids.d.ts +17 -0
- package/dist/prm/trajectory-store.d.ts +1 -1
- package/dist/services/diagnose-service.d.ts +7 -0
- package/dist/services/status-service.d.ts +18 -0
- package/dist/telemetry.d.ts +52 -1
- package/dist/tools/context-status.d.ts +15 -1
- package/dist/tools/repo-graph/ontology.d.ts +6 -0
- package/dist/tools/repo-graph/pack-query.d.ts +36 -0
- package/dist/tools/repo-graph/types.d.ts +198 -1
- package/dist/tools/repo-graph.d.ts +5 -3
- package/package.json +1 -1
- package/dist/cli/curator-llm-factory-24bfn7h1.js +0 -66
- package/dist/cli/guardrail-explain-b3k9xrx9.js +0 -67
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learning/operations health — bounded-window alarm registry (issue #2044).
|
|
3
|
+
*
|
|
4
|
+
* Lives in `src/health/`, NOT `src/observability/`: this module performs
|
|
5
|
+
* bounded artifact I/O (`.swarm/learning-health.json`) and imports telemetry,
|
|
6
|
+
* both of which the observability directory's zero-I/O contract forbids
|
|
7
|
+
* (enforced by `tests/unit/observability/no-io.test.ts`).
|
|
8
|
+
*
|
|
9
|
+
* This module owns the eight alarm families the observability series assigned
|
|
10
|
+
* to PR 16:
|
|
11
|
+
*
|
|
12
|
+
* 1. `headroom_dead_streak` — repeated zero/negative effective headroom
|
|
13
|
+
* 2. `model_limit_fallback` — context-limit resolution fell back off the
|
|
14
|
+
* host/live or user-override rungs
|
|
15
|
+
* 3. `retrieval_outcome_liveness` — retrieval → terminal receipt → application
|
|
16
|
+
* outcome chain stalled
|
|
17
|
+
* 4. `role_participation` — eligible workflow roles not participating
|
|
18
|
+
* 5. `promoted_fixture_share` — promoted-tier evidence dominated by
|
|
19
|
+
* non-field (fixture/synthetic-class) sources
|
|
20
|
+
* 6. `archive_activity_mismatch` — close archive empty/invalid while recorded
|
|
21
|
+
* activity predicted content
|
|
22
|
+
* 7. `recovery_ledger_pressure` — background delegation recovery ledger near
|
|
23
|
+
* its 4 MiB bound
|
|
24
|
+
* 8. `compaction_drop_coverage` — store compaction dropping/corrupting
|
|
25
|
+
* records across the six audited stores
|
|
26
|
+
*
|
|
27
|
+
* ## Contracts (issue #2044 items 5-10)
|
|
28
|
+
*
|
|
29
|
+
* - **Bounded windows with cooldown + hysteresis.** Every alarm raises only on
|
|
30
|
+
* its per-family condition inside a bounded window, re-emits at most once per
|
|
31
|
+
* cooldown interval (`sustained`), and recovers explicitly. Duplicate facts
|
|
32
|
+
* (same kind + timestamp) and late/out-of-order facts never storm alerts: the
|
|
33
|
+
* window is a monotonic append; a late fact counts but never rewinds
|
|
34
|
+
* `windowStartMs`.
|
|
35
|
+
* - **Per-canonical-project/session state with explicit eviction.** Session
|
|
36
|
+
* scopes are keyed `<projectRef>/<sessionRef>` when the producer knows its
|
|
37
|
+
* project directory and `u/<sessionRef>` when it does not (the chat-transform
|
|
38
|
+
* hooks receive no directory), so identical session ids under distinct
|
|
39
|
+
* projects never collide. Scope maps are FIFO-evicted at
|
|
40
|
+
* {@link MAX_HEALTH_SCOPES}; fact rings at {@link MAX_FACTS_PER_SCOPE}.
|
|
41
|
+
* - **No raw content.** Payloads and the persisted artifact carry counts,
|
|
42
|
+
* closed-vocabulary enums, booleans, millisecond timestamps, model/provider
|
|
43
|
+
* identity, and 16-hex salted session refs from
|
|
44
|
+
* `pseudonymousSessionRef` — never raw session ids, paths, queries, prompts,
|
|
45
|
+
* or responses (item 10).
|
|
46
|
+
* - **Persistence is transitions + compact per-scope counters ONLY** (item 9):
|
|
47
|
+
* what incident reconstruction needs. This module intentionally contains NO
|
|
48
|
+
* invocation-owned transient-retry or `nonTransientCircuit` state, so there is
|
|
49
|
+
* nothing of that class to persist or rehydrate — restarts resume health
|
|
50
|
+
* accumulation from the persisted counters, which is health state, not
|
|
51
|
+
* invocation state.
|
|
52
|
+
* - **Typed health-source registration, no fake sink** (item 8):
|
|
53
|
+
* {@link HEALTH_SOURCES} cites every real producer and reader file:line.
|
|
54
|
+
* There is deliberately NO `sink` source and NO "sink loss" value — issue
|
|
55
|
+
* #2047 / PR 19 must register its own real producer and reader.
|
|
56
|
+
*
|
|
57
|
+
* Every alarm is wired to production readers: the `/swarm status` Learning
|
|
58
|
+
* Health section and the `/swarm diagnose` learning-health check (both via
|
|
59
|
+
* {@link readLearningHealth}); `context_status` additionally exposes model-limit
|
|
60
|
+
* provenance directly.
|
|
61
|
+
*/
|
|
62
|
+
import type { ContextWindowSource } from '../config/context-window';
|
|
63
|
+
/** The eight alarm families owned by this module. */
|
|
64
|
+
export type LearningHealthAlarmId = 'headroom_dead_streak' | 'model_limit_fallback' | 'retrieval_outcome_liveness' | 'role_participation' | 'promoted_fixture_share' | 'archive_activity_mismatch' | 'recovery_ledger_pressure' | 'compaction_drop_coverage';
|
|
65
|
+
export type LearningHealthTransition = 'raised' | 'sustained' | 'recovered';
|
|
66
|
+
export type LearningHealthSeverity = 'warning' | 'critical';
|
|
67
|
+
export type LearningHealthScopeClass = 'session' | 'identity' | 'project';
|
|
68
|
+
/** Identifier of a producer subsystem feeding alarms (typed registration). */
|
|
69
|
+
export type HealthSourceId = 'context_budget' | 'model_limits' | 'knowledge_receipts' | 'curator_compliance' | 'promotion_evidence' | 'close_archive' | 'delegation_ledger' | 'store_health_events';
|
|
70
|
+
export interface HealthSourceRegistration {
|
|
71
|
+
/** file:line of the live producer call site. */
|
|
72
|
+
readonly producer: string;
|
|
73
|
+
/** file:line of every live reader of this source's data. */
|
|
74
|
+
readonly readers: readonly string[];
|
|
75
|
+
/** Alarms this source feeds. */
|
|
76
|
+
readonly alarms: readonly LearningHealthAlarmId[];
|
|
77
|
+
}
|
|
78
|
+
export declare const HEALTH_SOURCES: Readonly<Record<HealthSourceId, HealthSourceRegistration>>;
|
|
79
|
+
/** Per-family thresholds. Documented constants, deliberately not user config. */
|
|
80
|
+
export declare const LEARNING_HEALTH_ALARM_CONFIG: Readonly<{
|
|
81
|
+
headroom_dead_streak: Readonly<{
|
|
82
|
+
windowMs: 600000;
|
|
83
|
+
raiseFacts: 3;
|
|
84
|
+
cooldownMs: 1800000;
|
|
85
|
+
severity: LearningHealthSeverity;
|
|
86
|
+
}>;
|
|
87
|
+
model_limit_fallback: Readonly<{
|
|
88
|
+
windowMs: 1800000;
|
|
89
|
+
cooldownMs: 3600000;
|
|
90
|
+
severity: LearningHealthSeverity;
|
|
91
|
+
}>;
|
|
92
|
+
retrieval_outcome_liveness: Readonly<{
|
|
93
|
+
windowMs: 1800000;
|
|
94
|
+
cooldownMs: 900000;
|
|
95
|
+
severity: LearningHealthSeverity;
|
|
96
|
+
gap2StalenessMs: 600000;
|
|
97
|
+
}>;
|
|
98
|
+
role_participation: Readonly<{
|
|
99
|
+
windowMs: 86400000;
|
|
100
|
+
raiseFacts: 2;
|
|
101
|
+
cooldownMs: 43200000;
|
|
102
|
+
severity: LearningHealthSeverity;
|
|
103
|
+
}>;
|
|
104
|
+
promoted_fixture_share: Readonly<{
|
|
105
|
+
windowMs: 604800000;
|
|
106
|
+
raiseShare: 0.5;
|
|
107
|
+
clearShare: 0.3;
|
|
108
|
+
minEvidence: 4;
|
|
109
|
+
cooldownMs: 86400000;
|
|
110
|
+
severity: LearningHealthSeverity;
|
|
111
|
+
}>;
|
|
112
|
+
archive_activity_mismatch: Readonly<{
|
|
113
|
+
windowMs: 0;
|
|
114
|
+
cooldownMs: 86400000;
|
|
115
|
+
severity: LearningHealthSeverity;
|
|
116
|
+
}>;
|
|
117
|
+
recovery_ledger_pressure: Readonly<{
|
|
118
|
+
windowMs: 900000;
|
|
119
|
+
raisePct: 0.8;
|
|
120
|
+
clearPct: 0.7;
|
|
121
|
+
cooldownMs: 1800000;
|
|
122
|
+
severity: LearningHealthSeverity;
|
|
123
|
+
}>;
|
|
124
|
+
compaction_drop_coverage: Readonly<{
|
|
125
|
+
windowMs: 3600000;
|
|
126
|
+
corruptRaise: 1;
|
|
127
|
+
droppedRaise: 100;
|
|
128
|
+
cooldownMs: 3600000;
|
|
129
|
+
severity: LearningHealthSeverity;
|
|
130
|
+
}>;
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Receipt sources that count as FIELD evidence for the fixture-share alarm:
|
|
134
|
+
* real workflow actors in a real run. `delegate` is field-but-non-independent —
|
|
135
|
+
* the independence dimension belongs to the promotion gate
|
|
136
|
+
* (src/hooks/knowledge-types.ts:410-418) and is deliberately NOT duplicated
|
|
137
|
+
* here.
|
|
138
|
+
*/
|
|
139
|
+
export declare const FIELD_RECEIPT_SOURCES: ReadonlySet<string>;
|
|
140
|
+
/**
|
|
141
|
+
* Receipt sources that count as NON-FIELD (fixture/synthetic-class) evidence:
|
|
142
|
+
* authorized overrides, manual/migration imports, administrative gate
|
|
143
|
+
* releases, and `unknown` (fail-closed — a forged or missing label never counts
|
|
144
|
+
* as field).
|
|
145
|
+
*/
|
|
146
|
+
export declare const NON_FIELD_RECEIPT_SOURCES: ReadonlySet<string>;
|
|
147
|
+
interface PersistedTransition {
|
|
148
|
+
alarm: LearningHealthAlarmId;
|
|
149
|
+
transition: LearningHealthTransition;
|
|
150
|
+
severity: LearningHealthSeverity;
|
|
151
|
+
atMs: number;
|
|
152
|
+
coverageFacts: number;
|
|
153
|
+
}
|
|
154
|
+
export declare const _internals: {
|
|
155
|
+
now: () => number;
|
|
156
|
+
emitTelemetry: (payload: Record<string, unknown>) => void;
|
|
157
|
+
writeArtifact: (directory: string, contents: string) => Promise<void>;
|
|
158
|
+
readArtifact: (directory: string) => Promise<string | null>;
|
|
159
|
+
};
|
|
160
|
+
/** Alarm payload detail — counts/enums/refs only, never raw content. */
|
|
161
|
+
export interface AlarmEmitDetail {
|
|
162
|
+
sessionRef?: string;
|
|
163
|
+
model?: string;
|
|
164
|
+
provider?: string;
|
|
165
|
+
limitSource?: string;
|
|
166
|
+
denominatorFallback?: boolean;
|
|
167
|
+
pressurePct?: number;
|
|
168
|
+
band?: string;
|
|
169
|
+
sharePct?: number;
|
|
170
|
+
fieldCount?: number;
|
|
171
|
+
nonFieldCount?: number;
|
|
172
|
+
store?: string;
|
|
173
|
+
dropped?: number;
|
|
174
|
+
corrupt?: number;
|
|
175
|
+
retained?: number;
|
|
176
|
+
accepted?: number;
|
|
177
|
+
gapType?: 'membership_to_terminal' | 'terminal_to_application';
|
|
178
|
+
role?: string;
|
|
179
|
+
phase?: number;
|
|
180
|
+
reason?: string;
|
|
181
|
+
}
|
|
182
|
+
/** Serialize current health state to `.swarm/learning-health.json` (fire-and-forget). */
|
|
183
|
+
export declare function persistLearningHealth(directory: string): Promise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* Observe one context-budget evaluation. `dead` = usagePercent ≥ 1.0
|
|
186
|
+
* (zero/negative effective headroom). The alarm raises after
|
|
187
|
+
* {@link LEARNING_HEALTH_ALARM_CONFIG.headroom_dead_streak.raiseFacts} distinct
|
|
188
|
+
* dead observations in the window and recovers on a healthy observation below
|
|
189
|
+
* the warn threshold. Attribution, not suppression: the payload always carries
|
|
190
|
+
* `limit_source` and `denominator_fallback` so an operator can tell real
|
|
191
|
+
* exhaustion from a stale static-table denominator — the "fallback hides
|
|
192
|
+
* dead-headroom loops" defect this alarm exists to surface.
|
|
193
|
+
*/
|
|
194
|
+
export declare function observeContextHeadroom(input: {
|
|
195
|
+
sessionID: string;
|
|
196
|
+
/** Project directory when the producer knows it (threaded from the plugin
|
|
197
|
+
* wiring at handler construction); the chat-transform input itself carries
|
|
198
|
+
* none. Scopes key by `<projectRef>/<sessionRef>` when present. */
|
|
199
|
+
directory?: string;
|
|
200
|
+
usagePercent: number;
|
|
201
|
+
limit: number;
|
|
202
|
+
limitSource: string;
|
|
203
|
+
warnThreshold: number;
|
|
204
|
+
}): void;
|
|
205
|
+
/**
|
|
206
|
+
* Observe one model-limit resolution. Fallback-active when the resolution came
|
|
207
|
+
* from the static tables or the flat default (not host/live, not a user
|
|
208
|
+
* override); recovery when the same identity later resolves from host/override.
|
|
209
|
+
*/
|
|
210
|
+
export declare function observeModelLimitResolution(input: {
|
|
211
|
+
modelID?: string;
|
|
212
|
+
providerID?: string;
|
|
213
|
+
/** Project directory when the producer knows it (threaded through
|
|
214
|
+
* resolveModelLimit); identity scopes key project-prefixed when present. */
|
|
215
|
+
directory?: string;
|
|
216
|
+
resolution: ContextWindowSource;
|
|
217
|
+
/** Which override key class matched (compound/model/default) — the alias
|
|
218
|
+
* provenance for user-authored limits (issue #2044 item 2). */
|
|
219
|
+
aliasKeyClass?: 'compound' | 'model' | 'default';
|
|
220
|
+
/** True when a user-authored override failed usability validation and was
|
|
221
|
+
* skipped (never coerced) — surfaced durably, not just as a warning. */
|
|
222
|
+
invalidOverride?: boolean;
|
|
223
|
+
}): void;
|
|
224
|
+
/**
|
|
225
|
+
* Observe one receipt-ledger transition. Called from the ledger's post-lock
|
|
226
|
+
* observation drain where the project directory and the observation record are
|
|
227
|
+
* both in hand. Gap-1: membership committed without a terminal within the
|
|
228
|
+
* window. Gap-2: a terminal with outcome 'applied' without an authoritative
|
|
229
|
+
* application closure — either an `architect_marker`-sourced application
|
|
230
|
+
* outcome or any gate release (the release valve is one-way, so a release MUST
|
|
231
|
+
* count as closure). Gap-2 opens only past the gate's staleness horizon.
|
|
232
|
+
*/
|
|
233
|
+
export declare function observeReceiptTransition(input: {
|
|
234
|
+
directory: string;
|
|
235
|
+
kind: string;
|
|
236
|
+
traceId: string;
|
|
237
|
+
receiptOutcome?: string;
|
|
238
|
+
receiptSource?: string;
|
|
239
|
+
/**
|
|
240
|
+
* OPTIONAL membership commit time for gap-2 staleness anchoring. Intentionally
|
|
241
|
+
* not populated by the current ledger drain (PRR-008): anchoring gap-2
|
|
242
|
+
* eligibility to the TERMINAL time (the fallback when absent) is the
|
|
243
|
+
* conservative bound — it can only delay eligibility, never fire the alarm
|
|
244
|
+
* before the application gate's own staleness escalation has had its
|
|
245
|
+
* window. Kept as an explicit input so a future ledger observation can
|
|
246
|
+
* tighten the anchor without an API change.
|
|
247
|
+
*/
|
|
248
|
+
membershipCommittedAtMs?: number;
|
|
249
|
+
atMs?: number;
|
|
250
|
+
}): void;
|
|
251
|
+
/**
|
|
252
|
+
* Observe one curator phase-compliance pass. `gaps` carries the compliance
|
|
253
|
+
* observation types counted as participation gaps; `agentsUsed` is the set of
|
|
254
|
+
* roles that DID participate. The structural-zero guard keeps a single review
|
|
255
|
+
* window with no eligible opportunity from ever raising.
|
|
256
|
+
*/
|
|
257
|
+
export declare function observeCuratorCompliance(input: {
|
|
258
|
+
directory: string;
|
|
259
|
+
phase?: number;
|
|
260
|
+
gapTypes: readonly string[];
|
|
261
|
+
agentsUsed: readonly string[];
|
|
262
|
+
}): void;
|
|
263
|
+
/**
|
|
264
|
+
* Observe one promotion-evidence record. Classification is closed-vocabulary:
|
|
265
|
+
* field sources are real workflow actors; everything else (overrides, manual
|
|
266
|
+
* and migration imports, administrative releases, unknown) is non-field and
|
|
267
|
+
* `unknown` NEVER counts as field (fail-closed against forged labels).
|
|
268
|
+
*/
|
|
269
|
+
export declare function observePromotionEvidence(input: {
|
|
270
|
+
directory: string;
|
|
271
|
+
receiptSource: string | undefined;
|
|
272
|
+
}): void;
|
|
273
|
+
/**
|
|
274
|
+
* Observe one close-archive result. Raises when the archive is empty/invalid
|
|
275
|
+
* while recorded activity predicted content; recovers on the next valid,
|
|
276
|
+
* non-empty archive. Late-arriving activity never retro-raises — the payload
|
|
277
|
+
* records what was known at decision time.
|
|
278
|
+
*/
|
|
279
|
+
export declare function observeCloseArchive(input: {
|
|
280
|
+
directory: string;
|
|
281
|
+
archiveValid: boolean;
|
|
282
|
+
archiveEmpty: boolean;
|
|
283
|
+
activityPredictsContent: boolean;
|
|
284
|
+
}): void;
|
|
285
|
+
/**
|
|
286
|
+
* Observe one delegation-ledger health collection. Raises at pressure ≥ 0.8
|
|
287
|
+
* (near the 4 MiB recovery bound) or on the compact-overdue / fail-closed
|
|
288
|
+
* bands; clears below 0.7 (hysteresis). `uncertain` surfaces recovery
|
|
289
|
+
* observation failures as closed reason codes.
|
|
290
|
+
*/
|
|
291
|
+
export declare function observeDelegationLedgerPressure(input: {
|
|
292
|
+
directory: string;
|
|
293
|
+
pressurePct: number;
|
|
294
|
+
band: string;
|
|
295
|
+
uncertain?: boolean;
|
|
296
|
+
}): void;
|
|
297
|
+
/**
|
|
298
|
+
* Direct, directory-bearing store-health observation (final-critic finding 3):
|
|
299
|
+
* the six audited stores call this at their health-event emit sites, so family
|
|
300
|
+
* 8 is fed from its real producers from the FIRST event — not only after an
|
|
301
|
+
* operator opens a status surface.
|
|
302
|
+
*/
|
|
303
|
+
export declare function observeStoreHealth(input: {
|
|
304
|
+
directory: string;
|
|
305
|
+
kind: string;
|
|
306
|
+
payload: Record<string, unknown>;
|
|
307
|
+
}): void;
|
|
308
|
+
declare function observeStoreHealthEvent(event: string, data: Record<string, unknown>, directory?: string): void;
|
|
309
|
+
/**
|
|
310
|
+
* Idempotent no-op registration point (PR #2446 review): family 8 is fed
|
|
311
|
+
* DIRECTLY by all six audited stores via {@link observeStoreHealth}, so no
|
|
312
|
+
* telemetry listener is attached. The historical listener double-fed every
|
|
313
|
+
* store event (direct + listener observed the same emission into two scope
|
|
314
|
+
* namespaces); it was removed. This function remains as the documented
|
|
315
|
+
* registration seam so future feeds have one call site to wire — it performs
|
|
316
|
+
* no work today and never touches the plugin init path.
|
|
317
|
+
*/
|
|
318
|
+
export declare function ensureLearningHealth(): void;
|
|
319
|
+
/**
|
|
320
|
+
* Test teardown: clear all in-memory health state. Never used in production
|
|
321
|
+
* code paths.
|
|
322
|
+
*/
|
|
323
|
+
export declare function resetLearningHealthForTest(): void;
|
|
324
|
+
export interface ActiveLearningHealthAlarm {
|
|
325
|
+
alarm: LearningHealthAlarmId;
|
|
326
|
+
severity: LearningHealthSeverity;
|
|
327
|
+
scopeClass: LearningHealthScopeClass;
|
|
328
|
+
scopeRef: string;
|
|
329
|
+
ageMs: number;
|
|
330
|
+
coverageFacts: number;
|
|
331
|
+
transitionCount: number;
|
|
332
|
+
}
|
|
333
|
+
export interface LearningHealthSnapshot {
|
|
334
|
+
activeAlarms: readonly ActiveLearningHealthAlarm[];
|
|
335
|
+
totalTransitions: number;
|
|
336
|
+
updatedAtMs: number;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Read learning health for a project: rehydrate any persisted artifact,
|
|
340
|
+
* lazily evaluate window-based alarms (liveness gaps age into raises without a
|
|
341
|
+
* timer), and persist the refreshed state. Fail-open: any error yields an
|
|
342
|
+
* empty snapshot.
|
|
343
|
+
*/
|
|
344
|
+
export declare function readLearningHealth(directory: string): Promise<LearningHealthSnapshot>;
|
|
345
|
+
/** All transitions in the bounded ring (newest last). Test/diagnostic accessor. */
|
|
346
|
+
export declare function getLearningHealthTransitions(): readonly PersistedTransition[];
|
|
347
|
+
/**
|
|
348
|
+
* Tier-0 test exports (writing-tests skill): pure-or-near-pure internals that
|
|
349
|
+
* tests exercise directly. `observeStoreHealthEvent` is the shared core the
|
|
350
|
+
* public `observeStoreHealth` wraps; tests use it to drive family-8 logic
|
|
351
|
+
* without constructing a directory scope.
|
|
352
|
+
*/
|
|
353
|
+
export declare const _test_exports: {
|
|
354
|
+
observeStoreHealthEvent: typeof observeStoreHealthEvent;
|
|
355
|
+
};
|
|
356
|
+
export {};
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* to provide proactive context management guidance to the architect agent.
|
|
7
7
|
*/
|
|
8
8
|
import type { PluginConfig } from '../config';
|
|
9
|
+
import { observeContextHeadroom } from '../health/learning-health';
|
|
9
10
|
import { telemetry } from '../telemetry';
|
|
10
11
|
interface MessageInfo {
|
|
11
12
|
role: string;
|
|
@@ -34,13 +35,21 @@ interface MessageWithParts {
|
|
|
34
35
|
}
|
|
35
36
|
export declare const _internals: {
|
|
36
37
|
telemetryContextPruned: typeof telemetry.contextPruned;
|
|
38
|
+
observeContextHeadroom: typeof observeContextHeadroom;
|
|
37
39
|
};
|
|
38
40
|
/**
|
|
39
41
|
* Creates the experimental.chat.messages.transform hook for context budget tracking.
|
|
40
42
|
* Injects warnings when context usage exceeds configured thresholds.
|
|
41
43
|
* Only operates on messages for the architect agent.
|
|
42
44
|
*/
|
|
43
|
-
export declare function createContextBudgetHandler(config: PluginConfig, resolveAgentModel?: (agentName: string) => string | undefined
|
|
45
|
+
export declare function createContextBudgetHandler(config: PluginConfig, resolveAgentModel?: (agentName: string) => string | undefined,
|
|
46
|
+
/**
|
|
47
|
+
* Project directory (threaded from the plugin wiring at handler
|
|
48
|
+
* construction — the chat-transform hook input itself carries none). Used
|
|
49
|
+
* ONLY to scope + persist the #2044 headroom health observation; every
|
|
50
|
+
* budget behavior is identical without it.
|
|
51
|
+
*/
|
|
52
|
+
directory?: string): (_input: Record<string, never>, _output: {
|
|
44
53
|
messages?: MessageWithParts[];
|
|
45
54
|
}) => Promise<void>;
|
|
46
55
|
export {};
|
package/dist/hooks/curator.d.ts
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* This dual dispatch means agent lists are incomplete — they capture factory-dispatched
|
|
25
25
|
* curators but omit hook-dispatched ones. This is by design for hook-internal operations.
|
|
26
26
|
*/
|
|
27
|
+
import { observeCuratorCompliance } from '../health/learning-health';
|
|
27
28
|
import { checkRecommendations, recordEmittedRecommendations } from '../services/recommendation-ledger.js';
|
|
28
29
|
import { listSkills, parseDraftFrontmatter, retireOrMarkStale, retireSkill } from '../services/skill-generator.js';
|
|
29
30
|
import { getSkillVersion, reviseSkill } from '../services/skill-reviser.js';
|
|
@@ -51,6 +52,7 @@ export declare const _internals: {
|
|
|
51
52
|
checkPhaseCompliance: typeof checkPhaseCompliance;
|
|
52
53
|
normalizeAgentName: typeof normalizeAgentName;
|
|
53
54
|
autoRetireSkills: typeof autoRetireSkills;
|
|
55
|
+
observeCuratorCompliance: typeof observeCuratorCompliance;
|
|
54
56
|
/**
|
|
55
57
|
* Retained deliberately (issue #2038 §7). The three curator decision sites
|
|
56
58
|
* now read through `readSkillUsageEntriesWithCoverage` because a coverage
|
|
@@ -43,6 +43,8 @@ interface FinalAccountingOptions {
|
|
|
43
43
|
/** Same seam createContextBudgetHandler uses: resolves the
|
|
44
44
|
* configured target model for an agent name. */
|
|
45
45
|
resolveAgentModelFn?: (agentName: string) => string | undefined;
|
|
46
|
+
/** Project directory (#2044): scopes the model-limit health observation. */
|
|
47
|
+
directory?: string;
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
48
50
|
* One-shot-per-band warning suppression (#2107 §3), backed by the
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* live derivation replaced. They exist so a first-turn `messages.transform`
|
|
26
26
|
* consumer degrades to a plausible number instead of the flat 128 000 floor.
|
|
27
27
|
*/
|
|
28
|
+
import { type ContextWindowSource } from '../config/context-window';
|
|
29
|
+
import { observeModelLimitResolution } from '../health/learning-health';
|
|
28
30
|
/**
|
|
29
31
|
* Native model context limits (in tokens) when used on their native platform.
|
|
30
32
|
*
|
|
@@ -85,21 +87,46 @@ export declare function extractModelInfo(messages: MessageWithParts[]): {
|
|
|
85
87
|
* @returns the sessionID, or `undefined` when no message carries one.
|
|
86
88
|
*/
|
|
87
89
|
export declare function extractSessionId(messages: MessageWithParts[] | undefined): string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Coarse provenance class for a resolved model limit (issue #2044 item 1).
|
|
92
|
+
* Maps the fine-grained {@link ContextWindowSource} rung onto the five classes
|
|
93
|
+
* the issue names: `host` (the live `model.limit.context`), `override` (any
|
|
94
|
+
* user-authored `model_limits` entry), `provider_cap` / `native` (the two
|
|
95
|
+
* known-stale static tables), and `fallback` (the flat 128k default).
|
|
96
|
+
*/
|
|
97
|
+
export type ModelLimitSource = 'host' | 'override' | 'provider_cap' | 'native' | 'fallback';
|
|
98
|
+
/** Provenance-bearing result of {@link resolveModelLimit} (issue #2044). */
|
|
99
|
+
export interface ModelLimitResolution {
|
|
100
|
+
/** The resolved context limit in tokens. */
|
|
101
|
+
limit: number;
|
|
102
|
+
/** Coarse provenance class — the issue's enum. */
|
|
103
|
+
source: ModelLimitSource;
|
|
104
|
+
/** Which fine-grained resolution rung produced the limit. */
|
|
105
|
+
resolution: ContextWindowSource;
|
|
106
|
+
}
|
|
107
|
+
export declare function classifyModelLimitSource(resolution: ContextWindowSource): ModelLimitSource;
|
|
88
108
|
/**
|
|
89
109
|
* Static-table lookup used as `fallbackLookup` for
|
|
90
|
-
* {@link resolveContextWindow}. Preserves the historical precedence of
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* `
|
|
110
|
+
* {@link resolveContextWindow}. Preserves the historical precedence of the two
|
|
111
|
+
* tables relative to each other (provider cap first, then a longest-prefix
|
|
112
|
+
* native match), and says WHICH table matched so the resolution source can
|
|
113
|
+
* distinguish `static_provider_cap` from `static_native` (issue #2044).
|
|
114
|
+
* Reachable only when no live `model.limit.context` was available.
|
|
94
115
|
*/
|
|
95
|
-
export declare function lookupStaticModelLimit(modelID?: string, providerID?: string):
|
|
116
|
+
export declare function lookupStaticModelLimit(modelID?: string, providerID?: string): {
|
|
117
|
+
tokens: number;
|
|
118
|
+
table: 'provider_cap' | 'native';
|
|
119
|
+
} | undefined;
|
|
96
120
|
/**
|
|
97
|
-
* Resolves the context limit for a given model/provider combination
|
|
121
|
+
* Resolves the context limit for a given model/provider combination WITH
|
|
122
|
+
* provenance (issue #2044).
|
|
98
123
|
*
|
|
99
124
|
* Thin adapter over the single derivation in `src/config/context-window.ts` —
|
|
100
125
|
* this function exists so the `experimental.chat.messages.transform` consumers
|
|
101
|
-
* (`context-budget.ts`, `knowledge-injector.ts`, `tools/context-status.ts
|
|
102
|
-
* keep their existing
|
|
126
|
+
* (`context-budget.ts`, `knowledge-injector.ts`, `tools/context-status.ts`,
|
|
127
|
+
* `final-context-accounting.ts`) keep their existing
|
|
128
|
+
* `(modelID, providerID, overrides)` call shape while receiving the typed
|
|
129
|
+
* `{ limit, source }` provenance the observability series requires. All
|
|
103
130
|
* ordering logic lives in the shared resolver; see its module header.
|
|
104
131
|
*
|
|
105
132
|
* Resolution order (first usable value wins):
|
|
@@ -111,44 +138,48 @@ export declare function lookupStaticModelLimit(modelID?: string, providerID?: st
|
|
|
111
138
|
* match (both known-stale; see the module header)
|
|
112
139
|
* 6. `DEFAULT_MODEL_CONTEXT_TOKENS` (128000)
|
|
113
140
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* already outranked the tables.
|
|
119
|
-
* - The live `model.limit.context` was inserted above both tables, which is
|
|
120
|
-
* the entire point of this change.
|
|
121
|
-
*
|
|
122
|
-
* Any value that is not a finite number ≥ 1000 is skipped rather than used, so
|
|
123
|
-
* a malformed override or a catalog entry with `limit.context: 0` can never
|
|
124
|
-
* produce a `NaN` / `Infinity` percentage.
|
|
141
|
+
* Any value that is not a finite number ≥ 1000 (untrusted rungs) / ≥ 1 (user
|
|
142
|
+
* rungs) is SKIPPED, never coerced; skipped user overrides are surfaced via a
|
|
143
|
+
* bounded `invalid_override_skipped` observation instead of silently
|
|
144
|
+
* disappearing (issue #2044 item 2).
|
|
125
145
|
*
|
|
126
146
|
* @param modelID - The model identifier (e.g., "claude-sonnet-4-6", "gpt-5")
|
|
127
147
|
* @param providerID - The provider identifier (e.g., "github-copilot", "anthropic")
|
|
128
148
|
* @param configOverrides - User configuration overrides (`context_budget.model_limits`)
|
|
129
149
|
* @param liveContextLimit - The live `model.limit.context` recorded for this
|
|
130
150
|
* session by the `system.transform` hook, when one has been seen
|
|
131
|
-
* @returns The resolved
|
|
151
|
+
* @returns The resolved limit with coarse source class and fine-grained rung
|
|
132
152
|
*
|
|
133
153
|
* @example
|
|
134
154
|
* // Live value wins over the stale static tables
|
|
135
155
|
* resolveModelLimit("claude-sonnet-4-6", "github-copilot", {}, 200000)
|
|
136
|
-
* // Returns: 200000
|
|
156
|
+
* // Returns: { limit: 200000, source: 'host', resolution: 'live_model_limit' }
|
|
137
157
|
*
|
|
138
158
|
* @example
|
|
139
159
|
* // Explicit user override beats the live value
|
|
140
160
|
* resolveModelLimit("gpt-5", "github-copilot", { "github-copilot/gpt-5": 60000 }, 400000)
|
|
141
|
-
* // Returns: 60000
|
|
161
|
+
* // Returns: { limit: 60000, source: 'override', resolution: 'user_provider_model' }
|
|
142
162
|
*
|
|
143
163
|
* @example
|
|
144
164
|
* // No live value: falls back to the static table (prefix match)
|
|
145
165
|
* resolveModelLimit("claude-sonnet-4-6-20260301", "anthropic", {})
|
|
146
|
-
* // Returns: 200000
|
|
166
|
+
* // Returns: { limit: 200000, source: 'native', resolution: 'static_native' }
|
|
147
167
|
*
|
|
148
168
|
* @example
|
|
149
169
|
* // Malformed live value is ignored, not divided by
|
|
150
170
|
* resolveModelLimit(undefined, undefined, {}, 0)
|
|
151
|
-
* // Returns: 128000
|
|
171
|
+
* // Returns: { limit: 128000, source: 'fallback', resolution: 'static_default' }
|
|
152
172
|
*/
|
|
153
|
-
export declare function resolveModelLimit(modelID?: string, providerID?: string, configOverrides?: Record<string, number>, liveContextLimit?: unknown
|
|
173
|
+
export declare function resolveModelLimit(modelID?: string, providerID?: string, configOverrides?: Record<string, number>, liveContextLimit?: unknown,
|
|
174
|
+
/** Project directory (threaded from the consumers) — scopes the #2044
|
|
175
|
+
* fallback-health observation to the owning project. */
|
|
176
|
+
directory?: string): ModelLimitResolution;
|
|
177
|
+
/**
|
|
178
|
+
* Bounded observation seam (invariant-7 DI): routes the model-limit fallback
|
|
179
|
+
* fact into the learning-health registry. Tests replace this to avoid touching
|
|
180
|
+
* global health state; production uses the real observer.
|
|
181
|
+
*/
|
|
182
|
+
export declare const _internals: {
|
|
183
|
+
observeResolution: typeof observeModelLimitResolution;
|
|
184
|
+
};
|
|
154
185
|
export {};
|
|
@@ -389,4 +389,4 @@ export declare function buildSkillUsageHealthPayload(doc: SkillUsagePendingDocum
|
|
|
389
389
|
export declare function emitSkillUsageHealth(doc: SkillUsagePendingDocument, trigger: SkillUsageHealthPayload['trigger'], gauges: {
|
|
390
390
|
bytes: number;
|
|
391
391
|
limitBytes: number;
|
|
392
|
-
}): void;
|
|
392
|
+
}, directory?: string): void;
|