opencode-swarm 7.136.2 → 7.136.3
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/.opencode/skills/brainstorm/SKILL.md +1 -1
- package/.opencode/skills/clarify/SKILL.md +3 -3
- package/.opencode/skills/clarify-spec/SKILL.md +2 -2
- package/.opencode/skills/consult/SKILL.md +1 -1
- package/.opencode/skills/council/SKILL.md +1 -1
- package/.opencode/skills/critic-gate/SKILL.md +8 -3
- package/.opencode/skills/discover/SKILL.md +1 -1
- package/.opencode/skills/execute/SKILL.md +1 -1
- package/.opencode/skills/gate-attribution/SKILL.md +1 -1
- package/.opencode/skills/issue-ingest/SKILL.md +3 -3
- package/.opencode/skills/phase-wrap/SKILL.md +1 -1
- package/.opencode/skills/plan/SKILL.md +3 -3
- package/.opencode/skills/pre-phase-briefing/SKILL.md +1 -1
- package/.opencode/skills/resume/SKILL.md +1 -1
- package/.opencode/skills/specify/SKILL.md +1 -1
- package/dist/cli/{config-doctor-b67nb84b.js → config-doctor-g71mz50j.js} +2 -2
- package/dist/cli/{core-4z1s2ak1.js → core-jpjk2qvt.js} +1 -1
- package/dist/cli/{curation-policy-kvzhfaj1.js → curation-policy-zhyttjpa.js} +6 -6
- package/dist/cli/{curator-nrmj8bds.js → curator-36dxw38r.js} +25 -25
- package/dist/cli/{curator-llm-factory-x7kvry9x.js → curator-llm-factory-k2a7cv41.js} +25 -25
- package/dist/cli/{evidence-summary-service-cf8sz2bq.js → evidence-summary-service-nse06dqr.js} +7 -7
- package/dist/cli/{gate-evidence-aenyz6vt.js → gate-evidence-kdygjr56.js} +4 -4
- package/dist/cli/{guardrail-explain-5kd44rcj.js → guardrail-explain-1k337z5d.js} +26 -26
- package/dist/cli/{guardrail-log-aksrzqdx.js → guardrail-log-xbc9bvdt.js} +3 -3
- package/dist/cli/{hive-promoter-cy21rhnd.js → hive-promoter-daxrn62p.js} +25 -25
- package/dist/cli/{index-y0xaq4f3.js → index-0vq9gnqd.js} +8 -2
- package/dist/cli/{index-rw3f73aq.js → index-176zwqcq.js} +2 -2
- package/dist/cli/{index-kwwxevne.js → index-45y0y3xh.js} +5 -5
- package/dist/cli/{index-7ayaq27q.js → index-68tjkaqk.js} +1 -1
- package/dist/cli/{index-s0rbdp61.js → index-79pgzj9a.js} +4 -4
- package/dist/cli/{index-45t7w06b.js → index-7t3vjw5e.js} +1 -1
- package/dist/cli/{index-ey29aap6.js → index-b3jfcptk.js} +1 -1
- package/dist/cli/{index-sr2cynyw.js → index-brtg922w.js} +108 -51
- package/dist/cli/{index-7a2hm51h.js → index-cze4bq1x.js} +41 -0
- package/dist/cli/{index-mrtms113.js → index-d2sf9an1.js} +2 -2
- package/dist/cli/{index-wxyxf0bd.js → index-d61h3f3h.js} +2 -2
- package/dist/cli/{index-ckybsn6p.js → index-g2kpqpvh.js} +27 -27
- package/dist/cli/{index-37v2wxqe.js → index-g5rtcb1n.js} +1 -1
- package/dist/cli/{index-ad6j0m7k.js → index-gj5jerzz.js} +3 -3
- package/dist/cli/{index-c9ddxv4k.js → index-hh34tyv7.js} +1 -1
- package/dist/cli/{index-21115szq.js → index-kp5h245k.js} +5 -5
- package/dist/cli/{index-tcn457d5.js → index-kym0cctr.js} +1 -1
- package/dist/cli/{index-84nz7bhe.js → index-mgbpbs1f.js} +3 -3
- package/dist/cli/{index-m5fw4mer.js → index-n89fdxwg.js} +1 -1
- package/dist/cli/{index-z1tm47nj.js → index-ne28wyyc.js} +2 -2
- package/dist/cli/{index-wjm896ey.js → index-nfm9f10v.js} +1 -1
- package/dist/cli/{index-azghvnja.js → index-pff46kfv.js} +2 -2
- package/dist/cli/{index-wnz282j3.js → index-rtgqy0yg.js} +2 -2
- package/dist/cli/{index-09b9zncg.js → index-tncy55bp.js} +1 -1
- package/dist/cli/{index-vg3yx648.js → index-w6j1n5az.js} +1 -1
- package/dist/cli/{index-0755132s.js → index-wbdxmf1a.js} +6 -6
- package/dist/cli/{index-1kn24ja0.js → index-zcrvn579.js} +2 -2
- package/dist/cli/{index-s0vahtdm.js → index-zwh5dewz.js} +1 -1
- package/dist/cli/{index-dzyjb33e.js → index-zzhyws9g.js} +1 -1
- package/dist/cli/index.js +25 -25
- package/dist/cli/{knowledge-escalator-ta3xjrdj.js → knowledge-escalator-h7fspgph.js} +7 -7
- package/dist/cli/{knowledge-events-dk6banmz.js → knowledge-events-vkf7an5n.js} +5 -5
- package/dist/cli/{knowledge-link-mm1w967j.js → knowledge-link-zr40rnwr.js} +4 -4
- package/dist/cli/{knowledge-store-h3jz10bv.js → knowledge-store-s4976v9c.js} +5 -5
- package/dist/cli/{knowledge-validator-jsz1dxkr.js → knowledge-validator-64ppqy4y.js} +8 -8
- package/dist/cli/{pending-delegations-qajsxct0.js → pending-delegations-0h5b18p7.js} +3 -3
- package/dist/cli/{pr-subscriptions-qhr41epq.js → pr-subscriptions-jn0h047q.js} +3 -3
- package/dist/cli/{runner-2v413r74.js → runner-deeswadt.js} +5 -5
- package/dist/cli/{scan-cursor-48gwzh9c.js → scan-cursor-xbkae12h.js} +6 -6
- package/dist/cli/{schema-f937b9cs.js → schema-7jm70cab.js} +1 -1
- package/dist/cli/{scope-persistence-h2fpgxww.js → scope-persistence-5xc9ntdh.js} +4 -4
- package/dist/cli/{skill-generator-4p10ktw1.js → skill-generator-8gtq1ajr.js} +9 -9
- package/dist/cli/{telemetry-859khp82.js → telemetry-6678gya0.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-13btcj9g.js → worktree-collision-ownership-wt7cc850.js} +3 -3
- package/dist/config/schema.d.ts +10 -0
- package/dist/hooks/delegation-gate.d.ts +12 -1
- package/dist/hooks/gate-denial-tracker.d.ts +175 -0
- package/dist/hooks/guardrails/execution-episode.d.ts +41 -0
- package/dist/hooks/guardrails/execution-stall.d.ts +285 -0
- package/dist/hooks/guardrails/internals-guard.d.ts +117 -0
- package/dist/hooks/guardrails/messages-transform.d.ts +85 -0
- package/dist/hooks/trajectory-logger.d.ts +76 -0
- package/dist/index.js +476 -462
- package/dist/memory/schema.d.ts +3 -3
- package/dist/prm/index.d.ts +2 -0
- package/dist/state.d.ts +32 -0
- package/dist/telemetry.d.ts +66 -1
- package/dist/types/events.d.ts +14 -1
- package/package.json +2 -1
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
alreadyCuratedThisGeneration,
|
|
5
5
|
claimNextScanBatch,
|
|
6
6
|
getScanStatus
|
|
7
|
-
} from "./index-
|
|
8
|
-
import"./index-
|
|
7
|
+
} from "./index-zcrvn579.js";
|
|
8
|
+
import"./index-wbdxmf1a.js";
|
|
9
9
|
import"./index-ae75rja9.js";
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
10
|
+
import"./index-zzhyws9g.js";
|
|
11
|
+
import"./index-b3jfcptk.js";
|
|
12
12
|
import"./index-bk5tah7q.js";
|
|
13
13
|
import"./index-fsrp8wp3.js";
|
|
14
|
-
import"./index-
|
|
14
|
+
import"./index-tncy55bp.js";
|
|
15
15
|
import"./index-7g4c7s5r.js";
|
|
16
|
-
import"./index-
|
|
16
|
+
import"./index-cze4bq1x.js";
|
|
17
17
|
import"./index-y111zefa.js";
|
|
18
18
|
import"./index-zgwm4ryv.js";
|
|
19
19
|
import"./index-a76rekgs.js";
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
resolveScopeWithFallbacks,
|
|
13
13
|
writeScopeBindingToDisk,
|
|
14
14
|
writeScopeToDisk
|
|
15
|
-
} from "./index-
|
|
16
|
-
import"./index-
|
|
15
|
+
} from "./index-w6j1n5az.js";
|
|
16
|
+
import"./index-d61h3f3h.js";
|
|
17
17
|
import"./index-1kz6da87.js";
|
|
18
|
-
import"./index-
|
|
18
|
+
import"./index-tncy55bp.js";
|
|
19
19
|
import"./index-7g4c7s5r.js";
|
|
20
20
|
import"./index-bpmtbmy9.js";
|
|
21
|
-
import"./index-
|
|
21
|
+
import"./index-cze4bq1x.js";
|
|
22
22
|
import"./index-y111zefa.js";
|
|
23
23
|
import"./index-zgwm4ryv.js";
|
|
24
24
|
import"./index-a76rekgs.js";
|
|
@@ -33,21 +33,21 @@ import {
|
|
|
33
33
|
sanitizeSlug,
|
|
34
34
|
selectCandidateEntries,
|
|
35
35
|
writeEvalStub
|
|
36
|
-
} from "./index-
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
36
|
+
} from "./index-gj5jerzz.js";
|
|
37
|
+
import"./index-79pgzj9a.js";
|
|
38
|
+
import"./index-176zwqcq.js";
|
|
39
39
|
import"./index-rtry5xyf.js";
|
|
40
|
-
import"./index-
|
|
41
|
-
import"./index-
|
|
40
|
+
import"./index-wbdxmf1a.js";
|
|
41
|
+
import"./index-mgbpbs1f.js";
|
|
42
42
|
import"./index-ae75rja9.js";
|
|
43
|
-
import"./index-
|
|
44
|
-
import"./index-
|
|
43
|
+
import"./index-zzhyws9g.js";
|
|
44
|
+
import"./index-b3jfcptk.js";
|
|
45
45
|
import"./index-bk5tah7q.js";
|
|
46
46
|
import"./index-4rhhvd1a.js";
|
|
47
47
|
import"./index-fsrp8wp3.js";
|
|
48
|
-
import"./index-
|
|
48
|
+
import"./index-tncy55bp.js";
|
|
49
49
|
import"./index-7g4c7s5r.js";
|
|
50
|
-
import"./index-
|
|
50
|
+
import"./index-cze4bq1x.js";
|
|
51
51
|
import"./index-y111zefa.js";
|
|
52
52
|
import"./index-zgwm4ryv.js";
|
|
53
53
|
import"./index-a76rekgs.js";
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
scanDelegationFallbacksForRecovery,
|
|
10
10
|
scanDelegationsForRecovery
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-7t3vjw5e.js";
|
|
12
12
|
import"./index-4qzeef9h.js";
|
|
13
13
|
import"./index-fsrp8wp3.js";
|
|
14
|
-
import"./index-
|
|
14
|
+
import"./index-tncy55bp.js";
|
|
15
15
|
import"./index-7g4c7s5r.js";
|
|
16
16
|
import"./index-bpmtbmy9.js";
|
|
17
|
-
import"./index-
|
|
17
|
+
import"./index-cze4bq1x.js";
|
|
18
18
|
import"./index-z6xqpmqg.js";
|
|
19
19
|
import"./index-zjygnfay.js";
|
|
20
20
|
import {
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -527,6 +527,11 @@ export declare const GuardrailsConfigSchema: z.ZodObject<{
|
|
|
527
527
|
block_destructive_commands: z.ZodDefault<z.ZodBoolean>;
|
|
528
528
|
interpreter_allowed_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
529
529
|
shell_audit_log: z.ZodDefault<z.ZodBoolean>;
|
|
530
|
+
gate_denial_warn_threshold: z.ZodDefault<z.ZodNumber>;
|
|
531
|
+
gate_denial_stop_threshold: z.ZodDefault<z.ZodNumber>;
|
|
532
|
+
execution_stall_warn_calls: z.ZodDefault<z.ZodNumber>;
|
|
533
|
+
execution_stall_stop_calls: z.ZodDefault<z.ZodNumber>;
|
|
534
|
+
execution_stall_episode_minutes: z.ZodDefault<z.ZodNumber>;
|
|
530
535
|
}, z.core.$strip>;
|
|
531
536
|
export type GuardrailsConfig = z.infer<typeof GuardrailsConfigSchema>;
|
|
532
537
|
export declare const WatchdogConfigSchema: z.ZodObject<{
|
|
@@ -1884,6 +1889,11 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
1884
1889
|
block_destructive_commands: z.ZodDefault<z.ZodBoolean>;
|
|
1885
1890
|
interpreter_allowed_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1886
1891
|
shell_audit_log: z.ZodDefault<z.ZodBoolean>;
|
|
1892
|
+
gate_denial_warn_threshold: z.ZodDefault<z.ZodNumber>;
|
|
1893
|
+
gate_denial_stop_threshold: z.ZodDefault<z.ZodNumber>;
|
|
1894
|
+
execution_stall_warn_calls: z.ZodDefault<z.ZodNumber>;
|
|
1895
|
+
execution_stall_stop_calls: z.ZodDefault<z.ZodNumber>;
|
|
1896
|
+
execution_stall_episode_minutes: z.ZodDefault<z.ZodNumber>;
|
|
1887
1897
|
}, z.core.$strip>>;
|
|
1888
1898
|
watchdog: z.ZodOptional<z.ZodObject<{
|
|
1889
1899
|
scope_guard: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -221,6 +221,14 @@ export interface CoverageMissDiagnostic {
|
|
|
221
221
|
divergenceOffset: number;
|
|
222
222
|
corruptionHint?: string;
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Issue #2063 (A2): per-body cap, in characters, on the raw requirement body
|
|
226
|
+
* embedded verbatim in the ACCEPTANCE_FIELD_COVERAGE_MISMATCH error. Keeps the
|
|
227
|
+
* thrown message bounded even for an unusually long FR/SC body; when a body
|
|
228
|
+
* exceeds this cap the message states the cap and points at `.swarm/spec.md`
|
|
229
|
+
* for the remainder rather than growing the error without limit.
|
|
230
|
+
*/
|
|
231
|
+
export declare const ACCEPTANCE_EXPECTED_BODY_CAP = 2000;
|
|
224
232
|
export declare function describeCoverageMiss(params: {
|
|
225
233
|
rawExpectedBody: string;
|
|
226
234
|
rawAcceptanceText: string;
|
|
@@ -240,7 +248,9 @@ export declare function describeCoverageMiss(params: {
|
|
|
240
248
|
*
|
|
241
249
|
* @returns `{ covered: true }` when every id is present-and-covered or skipped;
|
|
242
250
|
* `{ covered: false, missingId }` naming the FIRST id whose body is not a
|
|
243
|
-
* substring of the ACCEPTANCE text
|
|
251
|
+
* substring of the ACCEPTANCE text, plus `expectedBody` — the RAW, UNTRIMMED
|
|
252
|
+
* requirement body for `missingId` (issue #2063 A2) — so the throw site can
|
|
253
|
+
* embed paste-ready remediation text instead of just pointing at a location.
|
|
244
254
|
*/
|
|
245
255
|
export declare function checkAcceptanceCoversFrRefs(params: {
|
|
246
256
|
acceptanceText: string;
|
|
@@ -250,6 +260,7 @@ export declare function checkAcceptanceCoversFrRefs(params: {
|
|
|
250
260
|
covered: boolean;
|
|
251
261
|
missingId?: string;
|
|
252
262
|
diagnostic?: CoverageMissDiagnostic;
|
|
263
|
+
expectedBody?: string;
|
|
253
264
|
};
|
|
254
265
|
interface MessageInfo {
|
|
255
266
|
role: string;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GATE DENIAL TRACKER (issue #2063, workstream B1)
|
|
3
|
+
*
|
|
4
|
+
* The architect session had no containment for a *denial-retry* loop: every
|
|
5
|
+
* fail-closed `tool.execute.before` hook throws, the host reports the throw as
|
|
6
|
+
* a tool rejection, and the model happily re-issues the identical dispatch —
|
|
7
|
+
* forever. Nothing counted the repeats, so nothing ever escalated.
|
|
8
|
+
*
|
|
9
|
+
* This module owns that counter. `noteGateDenial` is called from the single
|
|
10
|
+
* catch site wrapping the fail-closed chain in `src/index.ts`. It:
|
|
11
|
+
* 1. classifies the denial by the leading code token of the error message,
|
|
12
|
+
* 2. increments a per-(sessionID, toolName, discriminator, code) streak,
|
|
13
|
+
* 3. APPENDS (never rewrites) escalating guidance to the error message so the
|
|
14
|
+
* model reads it in the tool-rejection text, and
|
|
15
|
+
* 4. at the hard rung, pushes an advisory + emits telemetry.
|
|
16
|
+
*
|
|
17
|
+
* The DISCRIMINATOR (reviewer round-4 REQUIRED 2) is the canonicalized
|
|
18
|
+
* `subagent_type` of a `Task` call, and the empty string for every other tool.
|
|
19
|
+
* Without it the reset was too wide: `resetGateDenialStreaks` drops a whole
|
|
20
|
+
* (session, tool) prefix on any successful completion of that tool, so ONE
|
|
21
|
+
* successful `Task` → `explorer` erased a 4-deep `ACCEPTANCE_FIELD_REQUIRED`
|
|
22
|
+
* streak on `Task` → `coder`. Under the interleaving the loop actually
|
|
23
|
+
* exhibits — deny coder, delegate an explorer to investigate, deny coder again —
|
|
24
|
+
* the STOP rung was unreachable. Sub-scoping both the count and the reset by
|
|
25
|
+
* dispatch target makes a success clear only what plausibly succeeded.
|
|
26
|
+
*
|
|
27
|
+
* Invariants this module must not break:
|
|
28
|
+
* - The caller ALWAYS rethrows. Decoration is append-only, so the leading
|
|
29
|
+
* code token of the original message stays byte-identical and every
|
|
30
|
+
* existing consumer that substring-matches a gate code keeps working.
|
|
31
|
+
* - Abort/cancel errors are excluded entirely (a user hitting escape three
|
|
32
|
+
* times is not a loop) — they neither count nor reset an existing streak.
|
|
33
|
+
* - Nothing here may throw. A tracker failure must never convert a
|
|
34
|
+
* fail-closed denial into a different error.
|
|
35
|
+
*
|
|
36
|
+
* NOT to be confused with `swarmState.gateDenialCounts` (src/state.ts:768),
|
|
37
|
+
* which counts knowledge-application gate denials keyed by *critical-directive
|
|
38
|
+
* identity*. Different trigger, different key, different lifecycle.
|
|
39
|
+
*
|
|
40
|
+
* Eviction is modelled on `BoundedPendingScopeMap`
|
|
41
|
+
* (src/hooks/delegation-gate.ts:144-179) — TTL sweep plus a hard size cap — but
|
|
42
|
+
* deliberately re-implemented here rather than imported, because
|
|
43
|
+
* `delegation-gate.ts` is itself a member of the chain this module wraps and an
|
|
44
|
+
* import would create a cycle.
|
|
45
|
+
*/
|
|
46
|
+
/** Default streak length at which the "do not retry" guidance is appended. */
|
|
47
|
+
export declare const DEFAULT_GATE_DENIAL_WARN_THRESHOLD = 3;
|
|
48
|
+
/** Default streak length at which the hard STOP directive is appended. */
|
|
49
|
+
export declare const DEFAULT_GATE_DENIAL_STOP_THRESHOLD = 5;
|
|
50
|
+
/** Classification used when the message carries no recognisable code token. */
|
|
51
|
+
export declare const UNCLASSIFIED_GATE_DENIAL_CODE = "UNCLASSIFIED";
|
|
52
|
+
/**
|
|
53
|
+
* Sub-scope of a denial streak inside one (session, tool) pair.
|
|
54
|
+
*
|
|
55
|
+
* For a `Task` call this is the canonicalized dispatch target, so `mega_coder`
|
|
56
|
+
* and `coder` share one streak (matching `canonicalDispatchRole` in
|
|
57
|
+
* `guardrails/execution-stall.ts`). Every other tool — and a `Task` whose
|
|
58
|
+
* `subagent_type` is absent or not a string — yields `''`, which preserves the
|
|
59
|
+
* pre-discriminator behavior for them exactly.
|
|
60
|
+
*
|
|
61
|
+
* Deliberately reads `subagent_type` ONLY. `parseDelegationArgs`
|
|
62
|
+
* (`hooks/skill-propagation-gate.ts:400`) additionally falls back to the first
|
|
63
|
+
* non-empty line of the delegation PROMPT, which would turn arbitrary
|
|
64
|
+
* model-authored prose into a map key — an unbounded-cardinality hazard
|
|
65
|
+
* (invariant 8) and a way for the model to shatter its own streak into
|
|
66
|
+
* singletons by varying one line of text.
|
|
67
|
+
*
|
|
68
|
+
* Never throws.
|
|
69
|
+
*/
|
|
70
|
+
export declare function gateDenialDiscriminator(tool: string, args: unknown): string;
|
|
71
|
+
/**
|
|
72
|
+
* Derive the denial classification from an error message: the leading token up
|
|
73
|
+
* to the first `:`, trimmed.
|
|
74
|
+
*
|
|
75
|
+
* `'ACCEPTANCE_FIELD_COVERAGE_MISMATCH: task 1.1 ...'` -> `'ACCEPTANCE_FIELD_COVERAGE_MISMATCH'`
|
|
76
|
+
* `'FULL_AUTO_DENY [path_out_of_root]: ...'` -> `'FULL_AUTO_DENY [path_out_of_root]'`
|
|
77
|
+
* `'Blocked by skill propagation gate'` -> `'UNCLASSIFIED'` (no colon)
|
|
78
|
+
*
|
|
79
|
+
* The whole point of the classification is that repeats of the SAME cause share
|
|
80
|
+
* a value, so anything that cannot be a stable code (empty, absent, or longer
|
|
81
|
+
* than {@link MAX_CODE_LENGTH}) collapses to UNCLASSIFIED rather than producing
|
|
82
|
+
* a per-occurrence key.
|
|
83
|
+
*/
|
|
84
|
+
export declare function deriveGateDenialCode(message: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* True when the thrown value is a user/host abort rather than a policy denial.
|
|
87
|
+
* Aborts must not count toward a denial streak AND must not reset one: a user
|
|
88
|
+
* cancelling mid-loop does not mean the loop was resolved.
|
|
89
|
+
*/
|
|
90
|
+
export declare function isAbortLikeError(err: unknown): boolean;
|
|
91
|
+
/** The append-only warn rung. Exported so tests assert the exact wording. */
|
|
92
|
+
export declare function gateDenialWarnText(count: number, code: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* The append-only hard rung, modelled on `nonTransientHardStopMessage`
|
|
95
|
+
* (src/hooks/guardrails/nontransient-circuit.ts:336-354).
|
|
96
|
+
*/
|
|
97
|
+
export declare function gateDenialStopText(count: number, code: string, tool: string): string;
|
|
98
|
+
export interface GateDenialOptions {
|
|
99
|
+
/**
|
|
100
|
+
* `guardrails.enabled`. The thresholds live in the `guardrails` config block
|
|
101
|
+
* and the loader force-sets `enabled: false` when a user turns guardrails
|
|
102
|
+
* off, so that flag has to mean "no guardrails behavior" here too — otherwise
|
|
103
|
+
* the config surface lies. When false the denial is neither counted nor
|
|
104
|
+
* decorated, and no advisory or telemetry is produced. Defaults to true.
|
|
105
|
+
*/
|
|
106
|
+
enabled?: boolean;
|
|
107
|
+
/** `guardrails.gate_denial_warn_threshold` */
|
|
108
|
+
warnThreshold?: number;
|
|
109
|
+
/** `guardrails.gate_denial_stop_threshold` */
|
|
110
|
+
stopThreshold?: number;
|
|
111
|
+
}
|
|
112
|
+
export interface GateDenialOutcome {
|
|
113
|
+
/** Classification used for the streak key. */
|
|
114
|
+
code: string;
|
|
115
|
+
/** Streak length AFTER this denial. `0` when the denial was not counted. */
|
|
116
|
+
count: number;
|
|
117
|
+
/** Whether the warn rung fired on this denial. */
|
|
118
|
+
warned: boolean;
|
|
119
|
+
/** Whether the hard rung fired on this denial. */
|
|
120
|
+
stopped: boolean;
|
|
121
|
+
/** Whether the error message was mutated. */
|
|
122
|
+
decorated: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Count one fail-closed denial and, past the configured rungs, APPEND guidance
|
|
126
|
+
* to `err.message` in place.
|
|
127
|
+
*
|
|
128
|
+
* The caller is responsible for rethrowing the SAME object — mutating in place
|
|
129
|
+
* preserves `name`, `stack`, and any custom fields a gate attached, which
|
|
130
|
+
* constructing a replacement Error would destroy.
|
|
131
|
+
*
|
|
132
|
+
* `args` are the resolved `tool.execute.before` args of the DENIED call. They
|
|
133
|
+
* derive the discriminator, so a `Task` → `coder` streak and a `Task` →
|
|
134
|
+
* `explorer` streak are counted (and reset) separately. Omitting them is safe
|
|
135
|
+
* and reproduces the pre-discriminator single-bucket behavior.
|
|
136
|
+
*
|
|
137
|
+
* Never throws.
|
|
138
|
+
*/
|
|
139
|
+
export declare function noteGateDenial(sessionID: string, tool: string, err: unknown, options?: GateDenialOptions, args?: unknown): GateDenialOutcome;
|
|
140
|
+
/**
|
|
141
|
+
* Clear every denial streak for one (sessionID, toolName, discriminator) triple.
|
|
142
|
+
*
|
|
143
|
+
* Called when the fail-closed chain completes successfully for that tool: the
|
|
144
|
+
* dispatch that was being denied now passes, so the streak is over.
|
|
145
|
+
*
|
|
146
|
+
* Two levels of scoping, both load-bearing:
|
|
147
|
+
* - by TOOL, so a successful `read` does not erase an in-progress `Task`
|
|
148
|
+
* denial loop; and
|
|
149
|
+
* - by DISCRIMINATOR, so a successful `Task` → `explorer` does not erase an
|
|
150
|
+
* in-progress `Task` → `coder` denial loop. `args` are the resolved
|
|
151
|
+
* `tool.execute.before` args of the call that just SUCCEEDED, which is the
|
|
152
|
+
* only thing that can be said to have been resolved. Omitting them clears
|
|
153
|
+
* the `''` bucket only.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resetGateDenialStreaks(sessionID: string, tool: string, args?: unknown): void;
|
|
156
|
+
/**
|
|
157
|
+
* Drop all tracked streaks.
|
|
158
|
+
*
|
|
159
|
+
* A test/reset helper only — there is no `/swarm close` (or any other
|
|
160
|
+
* production) caller. Streak lifetime in production is governed by
|
|
161
|
+
* {@link GATE_DENIAL_TTL_MS}, the {@link MAX_TRACKED_DENIAL_STREAKS} LRU cap,
|
|
162
|
+
* and `resetGateDenialStreaks`.
|
|
163
|
+
*/
|
|
164
|
+
export declare function clearGateDenialStreaks(): void;
|
|
165
|
+
export declare const _test_exports: {
|
|
166
|
+
readonly MAX_TRACKED_DENIAL_STREAKS: 500;
|
|
167
|
+
readonly GATE_DENIAL_TTL_MS: number;
|
|
168
|
+
readonly MAX_CODE_LENGTH: 64;
|
|
169
|
+
readonly MAX_DISCRIMINATOR_LENGTH: 64;
|
|
170
|
+
readonly streakCount: () => number;
|
|
171
|
+
/** Read a streak length without mutating it. */
|
|
172
|
+
readonly peekStreak: (sessionID: string, tool: string, code: string, discriminator?: string) => number;
|
|
173
|
+
/** Force a streak's TTL into the past so eviction can be tested. */
|
|
174
|
+
readonly expireStreak: (sessionID: string, tool: string, code: string, discriminator?: string) => void;
|
|
175
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution-episode seam (issue #2063 B3/B5).
|
|
3
|
+
*
|
|
4
|
+
* An "execution episode" is the window in which a session has actually
|
|
5
|
+
* attempted execution work — a `Task` dispatch to a mutating/verifying role, or
|
|
6
|
+
* an `update_task_status(..., in_progress)` that succeeded. Containment levers
|
|
7
|
+
* that would produce false positives during ordinary conversation, planning, or
|
|
8
|
+
* read-only review are gated on the episode being ARMED.
|
|
9
|
+
*
|
|
10
|
+
* This module is deliberately narrow: it owns nothing but the read/write of the
|
|
11
|
+
* `executionEpisodeArmed` session field, so that
|
|
12
|
+
*
|
|
13
|
+
* - the CONSUMER side (B3's medium-band runaway counting in
|
|
14
|
+
* `messages-transform.ts`) has a single, testable predicate, and
|
|
15
|
+
* - the PRODUCER side (B5's arming/lapse policy in `execution-stall.ts`)
|
|
16
|
+
* has a single, testable mutator to call.
|
|
17
|
+
*
|
|
18
|
+
* Keeping the field access behind these two functions is what prevents the
|
|
19
|
+
* arming policy from being duplicated at each call site as it grows.
|
|
20
|
+
*
|
|
21
|
+
* Defaults are fail-open toward "not armed": an unknown session, a session with
|
|
22
|
+
* no state, and a session whose field was never initialised all read `false`,
|
|
23
|
+
* so a lever gated on this seam stays silent rather than firing on a session it
|
|
24
|
+
* knows nothing about.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Whether an execution episode is currently armed for `sessionID`.
|
|
28
|
+
*
|
|
29
|
+
* Returns `false` for unknown sessions.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isExecutionEpisodeArmed(sessionID: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Arm or disarm the execution episode for `sessionID`.
|
|
34
|
+
*
|
|
35
|
+
* No-ops for an unknown session: arming state is meaningless without a session
|
|
36
|
+
* to hang it on, and creating one here would let a containment lever
|
|
37
|
+
* materialise session state as a side effect.
|
|
38
|
+
*
|
|
39
|
+
* @returns `true` when the field was written, `false` when the session is unknown.
|
|
40
|
+
*/
|
|
41
|
+
export declare function setExecutionEpisodeArmed(sessionID: string, armed: boolean): boolean;
|