comisai 1.0.44 → 1.0.45

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 (80) hide show
  1. package/node_modules/@comis/agent/dist/spawn/sandbox-posture.d.ts +23 -0
  2. package/node_modules/@comis/agent/dist/spawn/sandbox-posture.js +27 -0
  3. package/node_modules/@comis/agent/dist/spawn/sub-agent-runner.js +5 -2
  4. package/node_modules/@comis/agent/package.json +1 -1
  5. package/node_modules/@comis/channels/package.json +1 -1
  6. package/node_modules/@comis/cli/package.json +1 -1
  7. package/node_modules/@comis/core/dist/domain/index.d.ts +2 -0
  8. package/node_modules/@comis/core/dist/domain/index.js +5 -0
  9. package/node_modules/@comis/core/dist/domain/rpc-error-classification.d.ts +49 -0
  10. package/node_modules/@comis/core/dist/domain/rpc-error-classification.js +62 -0
  11. package/node_modules/@comis/core/dist/exports/domain.d.ts +1 -1
  12. package/node_modules/@comis/core/dist/exports/domain.js +2 -0
  13. package/node_modules/@comis/core/package.json +1 -1
  14. package/node_modules/@comis/daemon/dist/api/graph-handlers/graph-mutate.js +5 -1
  15. package/node_modules/@comis/daemon/dist/api/rpc-dispatch.d.ts +15 -16
  16. package/node_modules/@comis/daemon/dist/api/rpc-dispatch.js +19 -32
  17. package/node_modules/@comis/daemon/dist/wiring/setup-gateway/setup-gateway-rpc.js +2 -1
  18. package/node_modules/@comis/daemon/package.json +1 -1
  19. package/node_modules/@comis/gateway/dist/rpc/method-router.js +13 -1
  20. package/node_modules/@comis/gateway/package.json +1 -1
  21. package/node_modules/@comis/infra/package.json +1 -1
  22. package/node_modules/@comis/memory/package.json +1 -1
  23. package/node_modules/@comis/observability/dist/trajectory/event-bus-bridge.d.ts +1 -0
  24. package/node_modules/@comis/observability/dist/trajectory/event-bus-bridge.js +10 -0
  25. package/node_modules/@comis/observability/dist/trajectory/translate-orchestration-payload.d.ts +1 -1
  26. package/node_modules/@comis/observability/dist/trajectory/translate-orchestration-payload.js +6 -0
  27. package/node_modules/@comis/observability/dist/trajectory/translate-payload.js +1 -0
  28. package/node_modules/@comis/observability/dist/trajectory/types.d.ts +1 -1
  29. package/node_modules/@comis/observability/dist/trajectory/types.js +7 -0
  30. package/node_modules/@comis/observability/package.json +1 -1
  31. package/node_modules/@comis/observability-otel/package.json +1 -1
  32. package/node_modules/@comis/orchestrator/package.json +1 -1
  33. package/node_modules/@comis/scheduler/package.json +1 -1
  34. package/node_modules/@comis/shared/package.json +1 -1
  35. package/node_modules/@comis/skills/package.json +1 -1
  36. package/node_modules/@comis/web/dist/assets/{agent-detail-DTS1F-Ms.js → agent-detail-lQF_QdY3.js} +1 -1
  37. package/node_modules/@comis/web/dist/assets/{agent-editor-Ciyu1WDy.js → agent-editor-t3rxtj2c.js} +1 -1
  38. package/node_modules/@comis/web/dist/assets/{agent-list-A1K8cnDs.js → agent-list-B3PEW7Eu.js} +1 -1
  39. package/node_modules/@comis/web/dist/assets/{billing-view-DeTSrDbU.js → billing-view-C4UJZTvI.js} +1 -1
  40. package/node_modules/@comis/web/dist/assets/{cache-health-BCWNSCJc.js → cache-health-CTOg1ZYH.js} +1 -1
  41. package/node_modules/@comis/web/dist/assets/{channel-detail-Dc9p_ikD.js → channel-detail-BqazWug8.js} +1 -1
  42. package/node_modules/@comis/web/dist/assets/{channel-list-Ky4JkuxX.js → channel-list-DYB8MGjC.js} +1 -1
  43. package/node_modules/@comis/web/dist/assets/{chat-console-Dz_CizN8.js → chat-console-C_EZsEon.js} +1 -1
  44. package/node_modules/@comis/web/dist/assets/{config-editor-CMnaLKV1.js → config-editor-5rFdpiyn.js} +2 -2
  45. package/node_modules/@comis/web/dist/assets/{context-dag-browser-B4SfvEGD.js → context-dag-browser-8RP0Dm9d.js} +1 -1
  46. package/node_modules/@comis/web/dist/assets/{context-engine-D56GG59R.js → context-engine-0Sl4qfpl.js} +1 -1
  47. package/node_modules/@comis/web/dist/assets/{delivery-view-G4cBmG5M.js → delivery-view-QQ-LYwDU.js} +1 -1
  48. package/node_modules/@comis/web/dist/assets/{diagnostics-view-Bf57kGOT.js → diagnostics-view-DjMOkstH.js} +1 -1
  49. package/node_modules/@comis/web/dist/assets/{ic-chat-message-CkDdrYHc.js → ic-chat-message-s52yIvwR.js} +1 -1
  50. package/node_modules/@comis/web/dist/assets/{ic-connection-dot-mggqNsPH.js → ic-connection-dot-3QDCBFHW.js} +1 -1
  51. package/node_modules/@comis/web/dist/assets/{ic-empty-state-f_kVNpuc.js → ic-empty-state-DIodMykW.js} +1 -1
  52. package/node_modules/@comis/web/dist/assets/ic-graph-canvas-Dllu1VH-.js +359 -0
  53. package/node_modules/@comis/web/dist/assets/{ic-tool-call-D1ykqLeH.js → ic-tool-call-CFexsEC4.js} +1 -1
  54. package/node_modules/@comis/web/dist/assets/{incident-view-Cd2e4cao.js → incident-view-C9r6FvdE.js} +1 -1
  55. package/node_modules/@comis/web/dist/assets/{index-dqPriKJN.js → index-IIyLteKK.js} +16 -16
  56. package/node_modules/@comis/web/dist/assets/{mcp-management-8zV6Sh-J.js → mcp-management-CON6d_R1.js} +1 -1
  57. package/node_modules/@comis/web/dist/assets/{media-config-fz862yVg.js → media-config-DNAN4cgu.js} +1 -1
  58. package/node_modules/@comis/web/dist/assets/{media-test-tDL7lri1.js → media-test-BOrE2MrP.js} +1 -1
  59. package/node_modules/@comis/web/dist/assets/{memory-inspector-aSmZ-bVd.js → memory-inspector-CdE2cWRI.js} +1 -1
  60. package/node_modules/@comis/web/dist/assets/{message-center-DWfIgL7i.js → message-center-BggZE_We.js} +1 -1
  61. package/node_modules/@comis/web/dist/assets/{models-H5of-8R4.js → models-BpdoS8xA.js} +1 -1
  62. package/node_modules/@comis/web/dist/assets/{observe-view-ExySKnkt.js → observe-view-D1ajhutj.js} +1 -1
  63. package/node_modules/@comis/web/dist/assets/{pipeline-builder-p1GmDJy5.js → pipeline-builder-DwLB9aCL.js} +1 -1
  64. package/node_modules/@comis/web/dist/assets/{pipeline-history-DQEU-Ieu.js → pipeline-history-DVSVvho7.js} +1 -1
  65. package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-Bu51TMIX.js → pipeline-history-detail-C3e5mGIt.js} +1 -1
  66. package/node_modules/@comis/web/dist/assets/{pipeline-list-DaYyj89m.js → pipeline-list-DYdQxTk4.js} +1 -1
  67. package/node_modules/@comis/web/dist/assets/{pipeline-monitor-DV_7bRn2.js → pipeline-monitor-Q48nN7ZK.js} +1 -1
  68. package/node_modules/@comis/web/dist/assets/{scheduler-D0YVlb55.js → scheduler-Drjol0QC.js} +1 -1
  69. package/node_modules/@comis/web/dist/assets/{security-78aeYyN2.js → security-DvcAVz_Q.js} +1 -1
  70. package/node_modules/@comis/web/dist/assets/{session-detail-D1yJ9diX.js → session-detail-Cv3O0UDP.js} +1 -1
  71. package/node_modules/@comis/web/dist/assets/{session-list-CxPzhPnX.js → session-list-BGVUpP_a.js} +1 -1
  72. package/node_modules/@comis/web/dist/assets/{setup-wizard-SjMlBTNp.js → setup-wizard-DZsr49mN.js} +2 -2
  73. package/node_modules/@comis/web/dist/assets/{skills-M6MQLY5D.js → skills-DP1dLFcB.js} +1 -1
  74. package/node_modules/@comis/web/dist/assets/{spend-governance-C0hIl9wq.js → spend-governance-D-IBKKqz.js} +1 -1
  75. package/node_modules/@comis/web/dist/assets/{subagents-CLCo4cfc.js → subagents-D0_m-5Pa.js} +1 -1
  76. package/node_modules/@comis/web/dist/assets/{workspace-manager-BzHAmYW2.js → workspace-manager-QmBrvxyy.js} +1 -1
  77. package/node_modules/@comis/web/dist/index.html +1 -1
  78. package/node_modules/@comis/web/package.json +1 -1
  79. package/package.json +16 -16
  80. package/node_modules/@comis/web/dist/assets/ic-graph-canvas-CBDFKlf5.js +0 -359
@@ -112,3 +112,26 @@ export interface SkillsPostureSlice {
112
112
  * Pure: no I/O, no config import beyond the structural {@link SkillsPostureSlice}.
113
113
  */
114
114
  export declare function resolvePostureFromSkills(skills: SkillsPostureSlice | undefined): SandboxPosture;
115
+ /**
116
+ * Thrown by the sub-agent spawn path (P0-C no-downgrade gate) when a child's
117
+ * sandbox posture is strictly LESS confined than its spawner's on ≥1 dimension.
118
+ *
119
+ * A TYPED refusal (mirrors {@link RequiredToolsUnreachableError} in `@comis/core`):
120
+ * the daemon's `classifyRpcError` matches it to `precondition`/**warn**, so this
121
+ * fail-closed SECURITY refusal does NOT read as an `internal`/**error** handler
122
+ * fault in an operator's ERROR-level health sweep (OBS-RPC-REFUSAL-CLASS,
123
+ * orchestration-excellence-20260701). The refuse decision, the
124
+ * `security:sandbox_downgrade_refused` event, and the message are all unchanged —
125
+ * this only carries the type so the dispatch layer can classify it correctly.
126
+ *
127
+ * `violatedDimensions` are enum LABELS only (never posture values/paths/hosts, §2.7).
128
+ *
129
+ * @allow-throw: spawn() is consumed exclusively by daemon RPC handlers
130
+ * (@allow-throw boundary in sub-agent-runner.ts); rpc-dispatch converts this to a
131
+ * JSON-RPC error response.
132
+ */
133
+ export declare class SandboxDowngradeError extends Error {
134
+ readonly kind: "sandbox_downgrade";
135
+ readonly violatedDimensions: readonly PostureDimension[];
136
+ constructor(message: string, violatedDimensions: readonly PostureDimension[]);
137
+ }
@@ -165,3 +165,30 @@ export function resolvePostureFromSkills(skills) {
165
165
  // filesystem / network / uid intentionally unset (present-but-inert, A1).
166
166
  };
167
167
  }
168
+ /**
169
+ * Thrown by the sub-agent spawn path (P0-C no-downgrade gate) when a child's
170
+ * sandbox posture is strictly LESS confined than its spawner's on ≥1 dimension.
171
+ *
172
+ * A TYPED refusal (mirrors {@link RequiredToolsUnreachableError} in `@comis/core`):
173
+ * the daemon's `classifyRpcError` matches it to `precondition`/**warn**, so this
174
+ * fail-closed SECURITY refusal does NOT read as an `internal`/**error** handler
175
+ * fault in an operator's ERROR-level health sweep (OBS-RPC-REFUSAL-CLASS,
176
+ * orchestration-excellence-20260701). The refuse decision, the
177
+ * `security:sandbox_downgrade_refused` event, and the message are all unchanged —
178
+ * this only carries the type so the dispatch layer can classify it correctly.
179
+ *
180
+ * `violatedDimensions` are enum LABELS only (never posture values/paths/hosts, §2.7).
181
+ *
182
+ * @allow-throw: spawn() is consumed exclusively by daemon RPC handlers
183
+ * (@allow-throw boundary in sub-agent-runner.ts); rpc-dispatch converts this to a
184
+ * JSON-RPC error response.
185
+ */
186
+ export class SandboxDowngradeError extends Error {
187
+ kind = "sandbox_downgrade";
188
+ violatedDimensions;
189
+ constructor(message, violatedDimensions) {
190
+ super(message);
191
+ this.name = "SandboxDowngradeError";
192
+ this.violatedDimensions = violatedDimensions;
193
+ }
194
+ }
@@ -16,7 +16,7 @@ import { createCoordinatorProgressFork, } from "./coordinator-progress-fork.js";
16
16
  import { sanitizeAssistantResponse } from "../provider/response/sanitize-pipeline.js";
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { classifyAbortReason, buildAnnouncementMessage, deliverAnnouncement, deliverFailureNotification, validateOutputs, sweepResultFiles, persistFailureRecord, } from "./sub-agent-result-processor.js";
19
- import { comparePosture } from "./sandbox-posture.js";
19
+ import { comparePosture, SandboxDowngradeError } from "./sandbox-posture.js";
20
20
  import { steerRun as steerRunHelper } from "./steer-run.js";
21
21
  // ---------------------------------------------------------------------------
22
22
  // Constants
@@ -703,7 +703,10 @@ export function createSubAgentRunner(deps) {
703
703
  childPosture,
704
704
  });
705
705
  // @allow-throw: spawn() consumed exclusively by daemon RPC handlers; @allow-throw boundary.
706
- throw new Error(`Spawn refused: child "${params.agentId}" sandbox posture is less confined than parent "${params.callerAgentId}" on: ${violated}.`);
706
+ // Typed (OBS-RPC-REFUSAL-CLASS): classifyRpcError maps SandboxDowngradeError to
707
+ // precondition/warn — this fail-closed SECURITY refusal must NOT read as an
708
+ // internal/error handler fault in an operator's ERROR-level health sweep.
709
+ throw new SandboxDowngradeError(`Spawn refused: child "${params.agentId}" sandbox posture is less confined than parent "${params.callerAgentId}" on: ${violated}.`, cmp.violatedDimensions);
707
710
  }
708
711
  }
709
712
  // Children check (bypassed for graph spawns)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/agent",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "AI agent executor, budget control, and session management for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/channels",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Chat platform adapters — Discord, Telegram, Slack, WhatsApp, Signal, iMessage, IRC, LINE",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/cli",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Command-line interface for the Comis AI agent platform",
@@ -35,3 +35,5 @@ export { ProviderFamilySchema, TranscriptToolCallIdModeSchema, ProviderCapabilit
35
35
  export type { ProviderFamily, TranscriptToolCallIdMode, ProviderCapabilities, } from "./provider-capabilities.js";
36
36
  export { SUB_AGENT_TOOL_DENYLIST, SUB_AGENT_TOOL_PROFILES, SUB_AGENT_TOOL_GROUPS, RequiredToolsUnreachableError, toolReachableGroups, computeReachableToolNames, } from "./sub-agent-tool-denylist.js";
37
37
  export type { UnreachableToolEntry } from "./sub-agent-tool-denylist.js";
38
+ export { classifyTypedRpcError } from "./rpc-error-classification.js";
39
+ export type { TypedRpcErrorKind, TypedRpcErrorClassification } from "./rpc-error-classification.js";
@@ -24,3 +24,8 @@ export { ToolSchemaProfileSchema, ToolCallArgumentsEncodingSchema, ModelCompatCo
24
24
  export { ProviderFamilySchema, TranscriptToolCallIdModeSchema, ProviderCapabilitiesSchema, } from "./provider-capabilities.js";
25
25
  // Sub-agent tool governance
26
26
  export { SUB_AGENT_TOOL_DENYLIST, SUB_AGENT_TOOL_PROFILES, SUB_AGENT_TOOL_GROUPS, RequiredToolsUnreachableError, toolReachableGroups, computeReachableToolNames, } from "./sub-agent-tool-denylist.js";
27
+ // RPC typed-refusal classification — the single source of truth the daemon
28
+ // rpc-dispatch classifier AND the @comis/gateway method-router classifier both
29
+ // delegate to, so intentional policy/security refusals classify consistently
30
+ // (warn, never internal/ERROR) at every log layer (OBS-RPC-REFUSAL-CLASS).
31
+ export { classifyTypedRpcError } from "./rpc-error-classification.js";
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Single source of truth for classifying a TYPED RPC refusal (OBS-RPC-REFUSAL-CLASS).
3
+ *
4
+ * ## Why this lives in `@comis/core`
5
+ * An RPC error is classified + logged at **two** layers: the daemon's
6
+ * `classifyRpcError` (`packages/daemon/src/api/rpc-dispatch.ts`) AND the
7
+ * `@comis/gateway` method-router trace wrapper (`classifyRpcMethodError`). The
8
+ * gateway is a lower-level library and **cannot `instanceof`** the daemon
9
+ * (`PreconditionError`/`ValidationError`/`AuthorizationError`), `@comis/agent`
10
+ * (`SandboxDowngradeError`), or local (`RequiredToolsUnreachableError`) error classes —
11
+ * the dependency direction forbids it.
12
+ *
13
+ * Before this module each layer hard-coded its own typed→kind mapping and they
14
+ * **drifted**: the gateway layer kept logging intentional policy/security refusals as
15
+ * `internal`/ERROR(50) long after the dispatch layer was fixed to `precondition`/warn,
16
+ * so a `logscan --level 50,60` operator health sweep STILL flagged a fail-closed
17
+ * refusal as an ERROR (found live, orchestration-excellence-20260701). Both layers now
18
+ * delegate here, keyed off the stable {@link Error.name} — the lowest-common-denominator
19
+ * signal available WITHOUT a cross-package import. **Add a new typed refusal in ONE
20
+ * place: {@link TYPED_RPC_ERROR_BY_NAME}.**
21
+ *
22
+ * ## Scope
23
+ * This recognizes the TYPED refusals only. Each caller keeps its OWN fallback for an
24
+ * UNRECOGNIZED error (the daemon defaults to `internal`/`error`; the gateway applies its
25
+ * message-substring heuristics then `internal`/`error`) — those fallbacks legitimately
26
+ * differ per layer and are deliberately NOT unified here.
27
+ *
28
+ * A typed refusal is an EXPECTED caller-side / policy / security outcome, never an
29
+ * internal handler fault, so its `level` is always `"warn"` and its `errorKind` is
30
+ * never `"internal"`.
31
+ *
32
+ * @module
33
+ */
34
+ /** The non-internal error kinds a typed RPC refusal classifies as. */
35
+ export type TypedRpcErrorKind = "precondition" | "validation" | "auth";
36
+ /** Classification of a recognized typed RPC refusal. `level` is always `"warn"`. */
37
+ export interface TypedRpcErrorClassification {
38
+ readonly errorKind: TypedRpcErrorKind;
39
+ readonly hint: string;
40
+ readonly level: "warn";
41
+ }
42
+ /**
43
+ * Classify a TYPED RPC refusal by its {@link Error.name}, or return `null` when the
44
+ * error is NOT a recognized typed refusal (the caller then applies its own fallback).
45
+ *
46
+ * Pure + dependency-free: no I/O, no error-class imports (keyed off the `.name` string),
47
+ * deterministic for a given input.
48
+ */
49
+ export declare function classifyTypedRpcError(err: unknown): TypedRpcErrorClassification | null;
@@ -0,0 +1,62 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Single source of truth for classifying a TYPED RPC refusal (OBS-RPC-REFUSAL-CLASS).
4
+ *
5
+ * ## Why this lives in `@comis/core`
6
+ * An RPC error is classified + logged at **two** layers: the daemon's
7
+ * `classifyRpcError` (`packages/daemon/src/api/rpc-dispatch.ts`) AND the
8
+ * `@comis/gateway` method-router trace wrapper (`classifyRpcMethodError`). The
9
+ * gateway is a lower-level library and **cannot `instanceof`** the daemon
10
+ * (`PreconditionError`/`ValidationError`/`AuthorizationError`), `@comis/agent`
11
+ * (`SandboxDowngradeError`), or local (`RequiredToolsUnreachableError`) error classes —
12
+ * the dependency direction forbids it.
13
+ *
14
+ * Before this module each layer hard-coded its own typed→kind mapping and they
15
+ * **drifted**: the gateway layer kept logging intentional policy/security refusals as
16
+ * `internal`/ERROR(50) long after the dispatch layer was fixed to `precondition`/warn,
17
+ * so a `logscan --level 50,60` operator health sweep STILL flagged a fail-closed
18
+ * refusal as an ERROR (found live, orchestration-excellence-20260701). Both layers now
19
+ * delegate here, keyed off the stable {@link Error.name} — the lowest-common-denominator
20
+ * signal available WITHOUT a cross-package import. **Add a new typed refusal in ONE
21
+ * place: {@link TYPED_RPC_ERROR_BY_NAME}.**
22
+ *
23
+ * ## Scope
24
+ * This recognizes the TYPED refusals only. Each caller keeps its OWN fallback for an
25
+ * UNRECOGNIZED error (the daemon defaults to `internal`/`error`; the gateway applies its
26
+ * message-substring heuristics then `internal`/`error`) — those fallbacks legitimately
27
+ * differ per layer and are deliberately NOT unified here.
28
+ *
29
+ * A typed refusal is an EXPECTED caller-side / policy / security outcome, never an
30
+ * internal handler fault, so its `level` is always `"warn"` and its `errorKind` is
31
+ * never `"internal"`.
32
+ *
33
+ * @module
34
+ */
35
+ // Keyed by `Error.name` (a `Map` — not object indexing — to keep the key set closed and
36
+ // avoid the `detect-object-injection` sink on the `.get(name)` lookup). The name strings
37
+ // are the CONTRACT with the error classes (each sets `this.name`); keep this map in sync
38
+ // when a class is renamed or a new typed refusal is introduced. The hints match the
39
+ // daemon's historical per-class hints so behavior is byte-identical after the two layers
40
+ // delegate here (and the gateway layer now inherits the knob-naming hints too).
41
+ const TYPED_RPC_ERROR_BY_NAME = new Map([
42
+ // Caller precondition failures (incl. gated-off policy refusals).
43
+ ["PreconditionError", { errorKind: "precondition", hint: "Caller precondition not met; check resource state before retry", level: "warn" }],
44
+ // Fail-closed SECURITY refusal (P0-C sub-agent sandbox no-downgrade gate).
45
+ ["SandboxDowngradeError", { errorKind: "precondition", hint: "Child sandbox posture is less confined than its spawner; align the child's skills sandbox config or set security.agentToAgent.sandboxNoDowngrade:false to allow", level: "warn" }],
46
+ // Caller-side validation failures.
47
+ ["ValidationError", { errorKind: "validation", hint: "Check parameter types and values against the schema", level: "warn" }],
48
+ ["RequiredToolsUnreachableError", { errorKind: "validation", hint: "Adjust required_tools and/or tool_groups per the per-tool hints in the error message", level: "warn" }],
49
+ // Expected authorization refusal (wrong-trust control-plane call).
50
+ ["AuthorizationError", { errorKind: "auth", hint: "Caller lacks admin trust for this control-plane method; use an admin-scoped token or the documented operator route (e.g. `comis explain` assembles obs reports offline)", level: "warn" }],
51
+ ]);
52
+ /**
53
+ * Classify a TYPED RPC refusal by its {@link Error.name}, or return `null` when the
54
+ * error is NOT a recognized typed refusal (the caller then applies its own fallback).
55
+ *
56
+ * Pure + dependency-free: no I/O, no error-class imports (keyed off the `.name` string),
57
+ * deterministic for a given input.
58
+ */
59
+ export function classifyTypedRpcError(err) {
60
+ const name = err instanceof Error ? err.name : "";
61
+ return TYPED_RPC_ERROR_BY_NAME.get(name) ?? null;
62
+ }
@@ -1,4 +1,4 @@
1
- export { AttachmentSchema, NormalizedMessageSchema, parseMessage, getMessageTraceId, NormalizedReactionSchema, parseReaction, TrustLevelSchema, MemorySourceSchema, MemoryEntrySchema, ExtractedEntitySchema, StructuredMemorySchema, MemoryExtractionResultSchema, MemoryEntitySchema, ToolCallSchema, TokenUsageSchema, AgentResponseSchema, SessionKeySchema, parseSessionKey, formatSessionKey, parseFormattedSessionKey, PollInputSchema, PollOptionResultSchema, NormalizedPollResultSchema, normalizePollDurationHours, RichButtonSchema, RichCardFieldSchema, RichCardSchema, RichEffectSchema, ApprovalRequestSchema, ApprovalResolutionSchema, SerializedApprovalRequestSchema, SerializedApprovalCacheEntrySchema, InjectionTypeSchema, CredentialMappingSchema, SecretRefSchema, isSecretRef, SecretRefOrStringSchema, DeliveryOriginSchema, createDeliveryOrigin, NodeStatusSchema, GraphStatusSchema, GraphNodeSchema, NodeExecutionStateSchema, ExecutionGraphSchema, GraphValidationError, parseExecutionGraph, topologicalSort, validateAndSortGraph, SubagentResultSchema, SubagentEndReasonSchema, parseSubagentResult, SubagentContextConfigSchema, NodeTypeIdSchema, ToolSchemaProfileSchema, ToolCallArgumentsEncodingSchema, ModelCompatConfigSchema, ProviderFamilySchema, TranscriptToolCallIdModeSchema, ProviderCapabilitiesSchema, SUB_AGENT_TOOL_DENYLIST, SUB_AGENT_TOOL_PROFILES, SUB_AGENT_TOOL_GROUPS, RequiredToolsUnreachableError, toolReachableGroups, computeReachableToolNames, MemoryExportEnvelopeSchema, MemoryExportEntrySchema, parseMemoryExportEnvelope, } from "../domain/index.js";
1
+ export { AttachmentSchema, NormalizedMessageSchema, parseMessage, getMessageTraceId, NormalizedReactionSchema, parseReaction, TrustLevelSchema, MemorySourceSchema, MemoryEntrySchema, ExtractedEntitySchema, StructuredMemorySchema, MemoryExtractionResultSchema, MemoryEntitySchema, ToolCallSchema, TokenUsageSchema, AgentResponseSchema, SessionKeySchema, parseSessionKey, formatSessionKey, parseFormattedSessionKey, PollInputSchema, PollOptionResultSchema, NormalizedPollResultSchema, normalizePollDurationHours, RichButtonSchema, RichCardFieldSchema, RichCardSchema, RichEffectSchema, ApprovalRequestSchema, ApprovalResolutionSchema, SerializedApprovalRequestSchema, SerializedApprovalCacheEntrySchema, InjectionTypeSchema, CredentialMappingSchema, SecretRefSchema, isSecretRef, SecretRefOrStringSchema, DeliveryOriginSchema, createDeliveryOrigin, NodeStatusSchema, GraphStatusSchema, GraphNodeSchema, NodeExecutionStateSchema, ExecutionGraphSchema, GraphValidationError, parseExecutionGraph, topologicalSort, validateAndSortGraph, SubagentResultSchema, SubagentEndReasonSchema, parseSubagentResult, SubagentContextConfigSchema, NodeTypeIdSchema, ToolSchemaProfileSchema, ToolCallArgumentsEncodingSchema, ModelCompatConfigSchema, ProviderFamilySchema, TranscriptToolCallIdModeSchema, ProviderCapabilitiesSchema, SUB_AGENT_TOOL_DENYLIST, SUB_AGENT_TOOL_PROFILES, SUB_AGENT_TOOL_GROUPS, RequiredToolsUnreachableError, toolReachableGroups, computeReachableToolNames, classifyTypedRpcError, MemoryExportEnvelopeSchema, MemoryExportEntrySchema, parseMemoryExportEnvelope, } from "../domain/index.js";
2
2
  export { BackgroundTaskOriginSchema } from "../domain/background-task-origin.js";
3
3
  export type { BackgroundTaskOrigin } from "../domain/background-task-origin.js";
4
4
  export { KEYLESS_PROVIDER_TYPES, KEYLESS_API_KEY_SENTINEL } from "../provider/keyless-providers.js";
@@ -37,6 +37,8 @@ ToolSchemaProfileSchema, ToolCallArgumentsEncodingSchema, ModelCompatConfigSchem
37
37
  ProviderFamilySchema, TranscriptToolCallIdModeSchema, ProviderCapabilitiesSchema,
38
38
  // Sub-agent tool governance
39
39
  SUB_AGENT_TOOL_DENYLIST, SUB_AGENT_TOOL_PROFILES, SUB_AGENT_TOOL_GROUPS, RequiredToolsUnreachableError, toolReachableGroups, computeReachableToolNames,
40
+ // RPC typed-refusal classification (single source of truth — OBS-RPC-REFUSAL-CLASS)
41
+ classifyTypedRpcError,
40
42
  // MemoryExportEnvelope
41
43
  MemoryExportEnvelopeSchema, MemoryExportEntrySchema, parseMemoryExportEnvelope, } from "../domain/index.js";
42
44
  export { BackgroundTaskOriginSchema } from "../domain/background-task-origin.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/core",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Core domain types, ports, event bus, security, and config for Comis",
@@ -17,6 +17,7 @@ import { randomUUID } from "node:crypto";
17
17
  import { existsSync, rmSync } from "node:fs";
18
18
  import { safePath, GraphDefineContract, GraphExecuteContract, GraphCancelContract, GraphSaveContract, GraphDeleteContract, GraphDeleteRunContract, stripInternalFields, requireCapability, } from "@comis/core";
19
19
  import { extractUserVariables, substituteUserVariables } from "../../graph/user-variables.js";
20
+ import { PreconditionError } from "../errors.js";
20
21
  import { IS_DEV, buildGraphInput, validateGraphWarnings, validateTypeConfigs, } from "./graph-helpers.js";
21
22
  // Authoring telemetry/audit helpers extracted to keep this file under the
22
23
  // graph-handlers/ 500-line cap (file-size cap; behavior byte-identical).
@@ -119,7 +120,10 @@ export function bindGraphMutateHandlers(deps) {
119
120
  // graph runs. A non-from_intent execute (no marker) is wholly unaffected —
120
121
  // byte-identical to pre-174.
121
122
  if (synthPattern && !deps.authoringConfig?.intentAction) {
122
- throw new Error("from_intent authoring is disabled by policy (orchestration.authoring.intentAction).");
123
+ // Typed (OBS-RPC-REFUSAL-CLASS): a gated-off policy refusal is a caller
124
+ // precondition failure, not an internal handler fault — classifyRpcError maps
125
+ // PreconditionError to precondition/warn so it doesn't read as a fleet ERROR.
126
+ throw new PreconditionError("from_intent authoring is disabled by policy (orchestration.authoring.intentAction).");
123
127
  }
124
128
  const userParams = stripInternalFields(rawParams);
125
129
  // M-1 (T-174-MARKER-LEAK): _synthesizedFromIntent is NOT in
@@ -16,23 +16,22 @@ export type { ApiDispatchDeps };
16
16
  /**
17
17
  * Classify an RPC error for structured logging.
18
18
  *
19
- * Accepts the raw error object (not just its message) so `instanceof`
20
- * checks against `PreconditionError` / `ValidationError` resolve. Returns
21
- * an ErrorKind, an actionable hint, AND a `level` (`"warn" | "error"`)
22
- * that the dispatcher uses to pick `logger.warn` vs `logger.error`. The
23
- * goal is to keep operator alerts meaningful: caller mistakes
24
- * (preconditions, validation) are warn-level via typed-class throws;
25
- * unmatched cases fall through to `error/internal`.
19
+ * Returns an ErrorKind, an actionable hint, AND a `level` (`"warn" | "error"`) that the
20
+ * dispatcher uses to pick `logger.warn` vs `logger.error`. The goal is to keep operator
21
+ * alerts meaningful: caller mistakes / policy / security refusals (`PreconditionError`,
22
+ * `ValidationError`, `AuthorizationError`, `RequiredToolsUnreachableError`,
23
+ * `SandboxDowngradeError`) are warn-level; unmatched cases fall through to `error/internal`.
26
24
  *
27
- * The legacy message-pattern (substring-match) fallbacks were deleted.
28
- * OBS-10 (reflect-obs-20260627): the admin-trust denials every `throw new Error(
29
- * "Admin access required …")` across the ~26 control-plane handlerswere migrated to
30
- * `throw new AuthorizationError(...)`, so an operator's wrong-trust call classifies as
31
- * `auth`/`warn` instead of `internal`/`error` (it was reading as a fleet ERROR + tripping
32
- * operator alerts though the gate fired correctly). The remaining bare-Error handlers
33
- * ("immutable" preconditions, etc.) still classify as `internal`/`error` until migrated
34
- * to `PreconditionError`/`ValidationError` that migration is incremental hardening. The
35
- * substring-fallback deletion is intentional; typed errors are the sanctioned path.
25
+ * The typed-refusal kind/hint/level mapping lives in `@comis/core`
26
+ * ({@link classifyTypedRpcError}) as the SINGLE source of truth, because the SAME error is
27
+ * ALSO classified by the `@comis/gateway` method-router trace wrapper which cannot
28
+ * `instanceof` these classes (dependency direction) and so keys off `Error.name`. Before
29
+ * that shared classifier the two layers drifted and the gateway kept logging intentional
30
+ * refusals as internal/ERROR after this layer was fixed (OBS-RPC-REFUSAL-CLASS,
31
+ * orchestration-excellence-20260701). **Add a new typed refusal in `@comis/core`, not
32
+ * here.** The legacy substring-match fallbacks remain deleted; typed errors are the
33
+ * sanctioned path (OBS-10: admin-trust denials throw `AuthorizationError`; bare-Error
34
+ * handlers still classify internal/error until migrated to a typed class).
36
35
  */
37
36
  export declare function classifyRpcError(err: unknown): {
38
37
  errorKind: ErrorKind;
@@ -11,8 +11,7 @@
11
11
  * the field set inline.
12
12
  * @module
13
13
  */
14
- import { PreconditionError, ValidationError, AuthorizationError } from "./errors.js";
15
- import { RequiredToolsUnreachableError, API_CONTRACTS_ORDERED, HANDLER_CAPABILITY_MAP, CapabilityDeniedError, parseFormattedSessionKey,
14
+ import { classifyTypedRpcError, API_CONTRACTS_ORDERED, HANDLER_CAPABILITY_MAP, CapabilityDeniedError, parseFormattedSessionKey,
16
15
  // Phase 217-05 (the keystone): the never-hang mode-aware deny decision.
17
16
  // resolveEffectiveMode = the EVICT-02 fail-closed primitive (Plan 01);
18
17
  // resolveAutonomy = the jail-leg server-side mode resolve (Plan 03); systemNowMs
@@ -122,39 +121,27 @@ const BINARY_PARAM_KEYS = ["source", "image", "video", "audio", "file"];
122
121
  /**
123
122
  * Classify an RPC error for structured logging.
124
123
  *
125
- * Accepts the raw error object (not just its message) so `instanceof`
126
- * checks against `PreconditionError` / `ValidationError` resolve. Returns
127
- * an ErrorKind, an actionable hint, AND a `level` (`"warn" | "error"`)
128
- * that the dispatcher uses to pick `logger.warn` vs `logger.error`. The
129
- * goal is to keep operator alerts meaningful: caller mistakes
130
- * (preconditions, validation) are warn-level via typed-class throws;
131
- * unmatched cases fall through to `error/internal`.
124
+ * Returns an ErrorKind, an actionable hint, AND a `level` (`"warn" | "error"`) that the
125
+ * dispatcher uses to pick `logger.warn` vs `logger.error`. The goal is to keep operator
126
+ * alerts meaningful: caller mistakes / policy / security refusals (`PreconditionError`,
127
+ * `ValidationError`, `AuthorizationError`, `RequiredToolsUnreachableError`,
128
+ * `SandboxDowngradeError`) are warn-level; unmatched cases fall through to `error/internal`.
132
129
  *
133
- * The legacy message-pattern (substring-match) fallbacks were deleted.
134
- * OBS-10 (reflect-obs-20260627): the admin-trust denials every `throw new Error(
135
- * "Admin access required …")` across the ~26 control-plane handlerswere migrated to
136
- * `throw new AuthorizationError(...)`, so an operator's wrong-trust call classifies as
137
- * `auth`/`warn` instead of `internal`/`error` (it was reading as a fleet ERROR + tripping
138
- * operator alerts though the gate fired correctly). The remaining bare-Error handlers
139
- * ("immutable" preconditions, etc.) still classify as `internal`/`error` until migrated
140
- * to `PreconditionError`/`ValidationError` that migration is incremental hardening. The
141
- * substring-fallback deletion is intentional; typed errors are the sanctioned path.
130
+ * The typed-refusal kind/hint/level mapping lives in `@comis/core`
131
+ * ({@link classifyTypedRpcError}) as the SINGLE source of truth, because the SAME error is
132
+ * ALSO classified by the `@comis/gateway` method-router trace wrapper which cannot
133
+ * `instanceof` these classes (dependency direction) and so keys off `Error.name`. Before
134
+ * that shared classifier the two layers drifted and the gateway kept logging intentional
135
+ * refusals as internal/ERROR after this layer was fixed (OBS-RPC-REFUSAL-CLASS,
136
+ * orchestration-excellence-20260701). **Add a new typed refusal in `@comis/core`, not
137
+ * here.** The legacy substring-match fallbacks remain deleted; typed errors are the
138
+ * sanctioned path (OBS-10: admin-trust denials throw `AuthorizationError`; bare-Error
139
+ * handlers still classify internal/error until migrated to a typed class).
142
140
  */
143
141
  export function classifyRpcError(err) {
144
- // Typed errors: instanceof checks. Add new typed classes here as
145
- // handlers migrate; do NOT re-introduce substring-match fallbacks.
146
- if (err instanceof PreconditionError)
147
- return { errorKind: "precondition", hint: "Caller precondition not met; check resource state before retry", level: "warn" };
148
- if (err instanceof ValidationError)
149
- return { errorKind: "validation", hint: "Check parameter types and values against the schema", level: "warn" };
150
- // OBS-10 (reflect-obs-20260627): an admin-trust denial is an EXPECTED authorization refusal, not an
151
- // internal/handler fault — warn/auth, so an operator's wrong-trust call doesn't read as a fleet ERROR.
152
- if (err instanceof AuthorizationError)
153
- return { errorKind: "auth", hint: "Caller lacks admin trust for this control-plane method; use an admin-scoped token or the documented operator route (e.g. `comis explain` assembles obs reports offline)", level: "warn" };
154
- // RequiredToolsUnreachableError is a caller-side validation failure (caller passed
155
- // invalid required_tools). Classify as validation/warn — NOT internal/error.
156
- if (err instanceof RequiredToolsUnreachableError)
157
- return { errorKind: "validation", hint: "Adjust required_tools and/or tool_groups per the per-tool hints in the error message", level: "warn" };
142
+ const typed = classifyTypedRpcError(err);
143
+ if (typed)
144
+ return typed;
158
145
  return { errorKind: "internal", hint: "Check the RPC method handler and its dependencies", level: "error" };
159
146
  }
160
147
  // ---------------------------------------------------------------------------
@@ -39,7 +39,8 @@ export function setupRpcBridge(deps) {
39
39
  }
40
40
  catch (err) {
41
41
  const errMsg = err instanceof Error ? err.message : String(err);
42
- const classified = classifyRpcError(errMsg);
42
+ // Pass the error OBJECT (not err.message) so classifyRpcError's typed-refusal recognition resolves (OBS-RPC-REFUSAL-CLASS).
43
+ const classified = classifyRpcError(err);
43
44
  gatewayLogger.debug({
44
45
  method,
45
46
  err: errMsg,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/daemon",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Background daemon and orchestrator for the Comis platform",
@@ -1,6 +1,6 @@
1
1
  import { JSONRPCServer, JSONRPCErrorException } from "json-rpc-2.0";
2
2
  import { checkScope } from "../auth/token-auth.js";
3
- import { tryGetContext } from "@comis/core";
3
+ import { classifyTypedRpcError, tryGetContext } from "@comis/core";
4
4
  /**
5
5
  * Map of method names to their required scope.
6
6
  */
@@ -45,6 +45,18 @@ export function createDynamicMethodRouter(initialMethods, logger) {
45
45
  * Classify an RPC method error for structured logging.
46
46
  */
47
47
  function classifyRpcMethodError(err) {
48
+ // OBS-RPC-REFUSAL-CLASS (orchestration-excellence-20260701): typed policy/security/
49
+ // validation refusals → non-internal (warn) via the SINGLE source of truth in
50
+ // `@comis/core`, which the daemon's `classifyRpcError` (rpc-dispatch.ts) ALSO delegates
51
+ // to. They reach this outer trace wrapper with their `Error.name` intact; this package
52
+ // cannot `instanceof` the daemon/@comis/agent error classes (dependency direction), and
53
+ // `classifyTypedRpcError` keys off that name — so the two log layers cannot drift (the
54
+ // drift is exactly what let this layer keep logging refusals as internal/ERROR after the
55
+ // dispatch layer was fixed). A refusal must NOT log error(50) — a health sweep counts it.
56
+ const typed = classifyTypedRpcError(err);
57
+ if (typed)
58
+ return { errorKind: typed.errorKind, hint: typed.hint };
59
+ // Unrecognized errors keep the gateway's own message-substring fallbacks, then internal.
48
60
  const msg = err instanceof Error ? err.message : String(err);
49
61
  const excerpt = msg.length > 120 ? msg.slice(0, 120) + "..." : msg;
50
62
  if (msg.includes("immutable"))
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/gateway",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "HTTP, JSON-RPC, and WebSocket gateway for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/infra",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Structured logging infrastructure for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/memory",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "SQLite memory, embeddings, and RAG storage for Comis agents",
@@ -68,6 +68,7 @@ export declare const TRAJECTORY_BRIDGE_MAPPING: {
68
68
  readonly "subagent:steered": "subagent.steered";
69
69
  readonly "security:sandbox_downgrade_refused": "security.sandbox_downgrade_refused";
70
70
  readonly "subagent:delivery_deadlettered": "subagent.delivery_deadlettered";
71
+ readonly "subagent:delivery_retried": "subagent.delivery_retried";
71
72
  readonly "subagent:budget_exceeded": "subagent.budget_exceeded";
72
73
  readonly "capability:audited": "capability.audited";
73
74
  readonly "graph:node_spawned": "graph.node_spawned";
@@ -150,6 +150,16 @@ export const TRAJECTORY_BRIDGE_MAPPING = {
150
150
  // the fleet lens via obs-persistence-wiring (the daemon-wide aggregate surface).
151
151
  "security:sandbox_downgrade_refused": "security.sandbox_downgrade_refused",
152
152
  "subagent:delivery_deadlettered": "subagent.delivery_deadlettered",
153
+ // OE-6b (orchestration-excellence-20260701-fullregression): the self-healing transient RETRY
154
+ // — the sibling of subagent:delivery_deadlettered. It was emitted by the announcement-batcher
155
+ // via `?.emit` (which the trajectory-event-types-known arch regex missed pre-fix), so it was
156
+ // bridged to NOTHING while its terminal sibling was fully wired — P0-B's self-heal was invisible
157
+ // to `comis explain` (spec §7/§10 + the "all 7 events bridged/surfaced" claim). Bridged here for
158
+ // per-session visibility (how many retries a completion took before landing). Content-free
159
+ // (translate-orchestration-payload.ts): runId + closed channelType + attempt count + transient tag
160
+ // ONLY. NOTE: unlike its deadlettered sibling, retried is trajectory-only for now (NOT yet a fleet
161
+ // health_signal/finding — a self-healed retry as a daemon-wide aggregate is a follow-up; §10).
162
+ "subagent:delivery_retried": "subagent.delivery_retried",
153
163
  "subagent:budget_exceeded": "subagent.budget_exceeded",
154
164
  // AUDIT-01 / TREE (v2.29 Phase 215 Plan 01): the per-capability authorization
155
165
  // decision for a gated call (allow + deny) — the spawn-tree's per-node
@@ -17,7 +17,7 @@
17
17
  * @module
18
18
  */
19
19
  /** The authoring / sub-agent orchestration EventBus event names the bridge maps. */
20
- export type OrchestrationBridgedEventName = "pipeline:authored" | "graph:repaired" | "graph:synthesized_from_intent" | "subagent:steered" | "security:sandbox_downgrade_refused" | "subagent:delivery_deadlettered" | "subagent:budget_exceeded" | "capability:audited" | "graph:node_spawned";
20
+ export type OrchestrationBridgedEventName = "pipeline:authored" | "graph:repaired" | "graph:synthesized_from_intent" | "subagent:steered" | "security:sandbox_downgrade_refused" | "subagent:delivery_deadlettered" | "subagent:delivery_retried" | "subagent:budget_exceeded" | "capability:audited" | "graph:node_spawned";
21
21
  /**
22
22
  * Translate a v2.27 authoring / orchestration EventBus payload into the
23
23
  * content-free `data` of its trajectory event. The envelope keys are stripped
@@ -47,6 +47,12 @@ export function translateOrchestrationPayload(eventName, payload) {
47
47
  // (retries-exhausted vs immediate-permanent) tag ONLY — NEVER the announcement body or
48
48
  // the error string (§2.7). timestamp envelope-only.
49
49
  return { runId: payload.runId, channelType: payload.channelType, transient: payload.transient };
50
+ case "subagent:delivery_retried":
51
+ // OE-6b (DELIVERY-03): the self-healing transient retry — run id + closed channelType +
52
+ // the 1-based attempt count + the transient tag ONLY (the `explain` view wants the attempt
53
+ // number so an operator can see HOW MANY retries a completion took before it landed) —
54
+ // NEVER the announcement body or the error string (§2.7). timestamp envelope-only.
55
+ return { runId: payload.runId, channelType: payload.channelType, attempt: payload.attempt, transient: payload.transient };
50
56
  case "subagent:budget_exceeded":
51
57
  // ORCH-OBS (BUDGET-03): the per-incident breach view for `comis explain` — graphId/
52
58
  // nodeId ids + the closed capSource + the two token NUMBERS (counts, §2.7-safe; the
@@ -274,6 +274,7 @@ export function translatePayload(eventName, rawPayload) {
274
274
  case "subagent:steered":
275
275
  case "security:sandbox_downgrade_refused":
276
276
  case "subagent:delivery_deadlettered":
277
+ case "subagent:delivery_retried": // OE-6b: the self-healing transient retry (sibling of delivery_deadlettered) — content-free {runId, channelType, attempt, transient}
277
278
  case "subagent:budget_exceeded":
278
279
  case "capability:audited":
279
280
  case "graph:node_spawned":
@@ -33,7 +33,7 @@ import type { ComisLogger } from "@comis/core";
33
33
  * skill → memory → delivery → lifecycle envelopes → control-plane sentinel).
34
34
  * Append-only — insertion order is part of the SemVer contract for v1.
35
35
  */
36
- export declare const TRAJECTORY_EVENT_TYPES: readonly ["session.started", "session.ended", "session.summary", "context.compiled", "prompt.submitted", "model.completed", "model.fallback_attempt", "model.fallback_exhausted", "model.auth_cooldown", "tool.call", "tool.result", "tool.timeout", "tool.policy_filtered", "tool.breaker_opened", "tool.breaker_reset", "tool.result_offloaded", "skill.prompt_loaded", "skill.prompt_invoked", "memory.skill_used", "memory.skill_surfaced", "memory.injected", "memory.recalled", "memory.reranked", "memory.generation_quality", "cache.break", "learning.outcome_observed", "learning.memory_demoted", "learning.memory_evicted", "learning.memory_failure_attributed", "reflect.admitted", "reflect.funnel", "learning.skill_promoted", "learning.skill_demoted", "pipeline.authored", "graph.repaired", "graph.synthesized_from_intent", "subagent.steered", "security.sandbox_downgrade_refused", "subagent.delivery_deadlettered", "subagent.budget_exceeded", "capability.audited", "graph.node_spawned", "background_task.promoted", "background_task.completed", "background_task.failed", "terminal.drive_promoted", "delivery.queued", "delivery.dispatched", "trace.metadata", "trace.artifacts", "trace.truncated", "trace.write_failures", "queue.enqueued", "queue.dequeued", "queue.overflow", "queue.coalesced", "execution.aborted", "execution.budget_warning", "execution.prompt_timeout", "execution.output_escalated", "execution.replay_recovered", "execution.tool_schema_unsupported", "security.injection_detected", "sender.blocked", "delivery.retry", "delivery.retry_exhausted", "delivery.markdown_fallback", "mcp.disconnected", "mcp.reconnecting", "mcp.reconnect_failed", "mcp.reconnected", "mcp.tools_changed", "channel.health_changed", "channel.lifecycle", "security.memory_tainted", "security.warn", "compaction.started", "compaction.flush", "compaction.recommended", "context.budget", "context.evicted", "context.masked", "context.reread", "context.overflow", "context.integrity", "context.rehydrated", "context.script_zero_hit", "context.summary_language_mismatch", "approval.requested", "approval.resolved", "dedup.duplicate_inbound", "health.budget_exceeded", "session.transcript.entry", "image.requested", "image.generated", "image.delivered", "image.failed", "media.vision.requested", "media.vision.completed", "media.vision.failed", "video.requested", "video.submitted", "video.generated", "video.delivered", "video.failed", "media.stt.requested", "media.stt.completed", "media.stt.failed", "media.tts.requested", "media.tts.completed", "media.tts.failed", "spend.warning", "spend.exceeded", "spend.unpriceable"];
36
+ export declare const TRAJECTORY_EVENT_TYPES: readonly ["session.started", "session.ended", "session.summary", "context.compiled", "prompt.submitted", "model.completed", "model.fallback_attempt", "model.fallback_exhausted", "model.auth_cooldown", "tool.call", "tool.result", "tool.timeout", "tool.policy_filtered", "tool.breaker_opened", "tool.breaker_reset", "tool.result_offloaded", "skill.prompt_loaded", "skill.prompt_invoked", "memory.skill_used", "memory.skill_surfaced", "memory.injected", "memory.recalled", "memory.reranked", "memory.generation_quality", "cache.break", "learning.outcome_observed", "learning.memory_demoted", "learning.memory_evicted", "learning.memory_failure_attributed", "reflect.admitted", "reflect.funnel", "learning.skill_promoted", "learning.skill_demoted", "pipeline.authored", "graph.repaired", "graph.synthesized_from_intent", "subagent.steered", "security.sandbox_downgrade_refused", "subagent.delivery_deadlettered", "subagent.delivery_retried", "subagent.budget_exceeded", "capability.audited", "graph.node_spawned", "background_task.promoted", "background_task.completed", "background_task.failed", "terminal.drive_promoted", "delivery.queued", "delivery.dispatched", "trace.metadata", "trace.artifacts", "trace.truncated", "trace.write_failures", "queue.enqueued", "queue.dequeued", "queue.overflow", "queue.coalesced", "execution.aborted", "execution.budget_warning", "execution.prompt_timeout", "execution.output_escalated", "execution.replay_recovered", "execution.tool_schema_unsupported", "security.injection_detected", "sender.blocked", "delivery.retry", "delivery.retry_exhausted", "delivery.markdown_fallback", "mcp.disconnected", "mcp.reconnecting", "mcp.reconnect_failed", "mcp.reconnected", "mcp.tools_changed", "channel.health_changed", "channel.lifecycle", "security.memory_tainted", "security.warn", "compaction.started", "compaction.flush", "compaction.recommended", "context.budget", "context.evicted", "context.masked", "context.reread", "context.overflow", "context.integrity", "context.rehydrated", "context.script_zero_hit", "context.summary_language_mismatch", "approval.requested", "approval.resolved", "dedup.duplicate_inbound", "health.budget_exceeded", "session.transcript.entry", "image.requested", "image.generated", "image.delivered", "image.failed", "media.vision.requested", "media.vision.completed", "media.vision.failed", "video.requested", "video.submitted", "video.generated", "video.delivered", "video.failed", "media.stt.requested", "media.stt.completed", "media.stt.failed", "media.tts.requested", "media.tts.completed", "media.tts.failed", "spend.warning", "spend.exceeded", "spend.unpriceable"];
37
37
  /** Closed union of trajectory event type strings. */
38
38
  export type TrajectoryEventType = (typeof TRAJECTORY_EVENT_TYPES)[number];
39
39
  /**
@@ -138,6 +138,13 @@ export const TRAJECTORY_EVENT_TYPES = [
138
138
  // landing); the other two ride whichever session bridge is active when they fire.
139
139
  "security.sandbox_downgrade_refused",
140
140
  "subagent.delivery_deadlettered",
141
+ // OE-6b (orchestration-excellence-20260701-fullregression): the self-healing transient
142
+ // RETRY — the sibling of subagent.delivery_deadlettered. Emitted by the announcement-batcher
143
+ // via `?.emit` (which the trajectory-event-types-known arch regex missed pre-fix), so it was
144
+ // bridged to NOTHING while its terminal sibling was fully wired — P0-B's self-heal was invisible
145
+ // to `comis explain` (spec §7/§10 + the "all 7 bridged" claim). Content-free: runId + closed
146
+ // channelType + attempt count + the transient tag ONLY — never an announcement body / error string.
147
+ "subagent.delivery_retried",
141
148
  "subagent.budget_exceeded",
142
149
  // AUDIT-01 / TREE (v2.29 Phase 215 Plan 01): the per-capability authorization
143
150
  // decision for a gated call — the spawn-tree's per-node producer (Plan 03's
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/observability",
3
3
  "private": true,
4
- "version": "1.0.44",
4
+ "version": "1.0.45",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Observability substrate (queued writer, payload bounding, sanitization, path guards) for Comis diagnostics artifacts",