@etiquekit/etq 1.0.11 → 1.0.13

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 (149) hide show
  1. package/AGENTS.md +19 -26
  2. package/LICENSE +2 -3
  3. package/NOTICE +6 -4
  4. package/QuickStart.md +35 -47
  5. package/README.md +54 -56
  6. package/bin/etiquette +1 -5
  7. package/bin/etiquette-core +1 -5
  8. package/docs/ARCHITECTURE.md +5 -5
  9. package/docs/CODEX_CLIENT_COMPATIBILITY.md +1 -1
  10. package/docs/CONCEPTS.md +7 -23
  11. package/docs/CONCEPT_STATUS.md +66 -0
  12. package/docs/CORE_PROFILE.md +3 -5
  13. package/docs/LANE_PROVISIONING.md +7 -2
  14. package/docs/README.md +4 -4
  15. package/docs/RELEASE_SURFACE_AUDIT.md +7 -6
  16. package/docs/SEAT_DISCIPLINE.md +55 -91
  17. package/docs/SEAT_PROVISIONING.md +19 -22
  18. package/docs/TEAM_HANDOFF.md +21 -21
  19. package/docs/WORKTREE_QOL.md +7 -6
  20. package/docs/contracts/ledger-entry/README.md +11 -11
  21. package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +3 -3
  22. package/docs/contracts/ledger-entry/ledger-entry.v0.md +8 -8
  23. package/package.json +11 -11
  24. package/packages/control/src/authority/lease.ts +261 -0
  25. package/packages/control/src/authority/node-delegation.ts +257 -0
  26. package/packages/control/src/authority/rig-conductor.ts +632 -0
  27. package/packages/control/src/cli/argv.ts +155 -0
  28. package/packages/control/src/cli/commands/console.ts +200 -0
  29. package/packages/control/src/cli/commands/dispatch-core.ts +89 -0
  30. package/packages/control/src/cli/commands/dispatch.ts +279 -0
  31. package/packages/control/src/cli/commands/harness.ts +89 -0
  32. package/packages/control/src/cli/commands/hook.ts +50 -0
  33. package/packages/control/src/cli/commands/ledger.ts +91 -0
  34. package/packages/control/src/cli/commands/local-workflow.ts +4686 -0
  35. package/packages/control/src/cli/commands/memory.ts +445 -0
  36. package/packages/control/src/cli/commands/release.ts +108 -0
  37. package/packages/control/src/cli/commands/rubric.ts +103 -0
  38. package/packages/control/src/cli/commands/seat.ts +179 -0
  39. package/packages/control/src/cli/commands/session.ts +127 -0
  40. package/packages/control/src/cli/commands/supervision.ts +246 -0
  41. package/packages/control/src/cli/commands/sync.ts +119 -0
  42. package/packages/control/src/cli/commands/workflow.ts +86 -0
  43. package/packages/control/src/cli/commands/workspace.ts +50 -0
  44. package/packages/control/src/cli/core-usage.ts +34 -0
  45. package/packages/control/src/cli/prompt.ts +67 -0
  46. package/packages/control/src/cli/supervision-deps.ts +44 -0
  47. package/packages/control/src/cli/usage.ts +241 -0
  48. package/packages/control/src/cli.ts +207 -0
  49. package/packages/control/src/core-cli.ts +50 -0
  50. package/packages/control/src/dispatch/decision.ts +202 -0
  51. package/packages/control/src/dispatch/projection.ts +293 -0
  52. package/packages/control/src/dispatch/record.ts +153 -0
  53. package/packages/control/src/engagement/project.ts +170 -0
  54. package/packages/control/src/fs.ts +19 -0
  55. package/packages/control/src/harness/pruning.ts +406 -0
  56. package/packages/control/src/hooks/dispatcher.ts +117 -0
  57. package/packages/control/src/hooks/outbox.ts +86 -0
  58. package/packages/control/src/hooks/sanitize.ts +6 -0
  59. package/packages/control/src/hooks/types.ts +34 -0
  60. package/packages/control/src/index.ts +384 -0
  61. package/packages/control/src/ledger/entry.ts +303 -0
  62. package/packages/control/src/ledger/indexer.ts +542 -0
  63. package/packages/control/src/memory/context.ts +149 -0
  64. package/packages/control/src/memory/drain-import.ts +207 -0
  65. package/packages/control/src/memory/indexer.ts +284 -0
  66. package/packages/control/src/memory/query.ts +75 -0
  67. package/packages/control/src/memory/sanitize.ts +50 -0
  68. package/packages/control/src/memory/sharded-drain-import.ts +212 -0
  69. package/packages/control/src/memory/status.ts +211 -0
  70. package/packages/control/src/memory/store-lifecycle.ts +509 -0
  71. package/packages/control/src/memory/store.ts +284 -0
  72. package/packages/control/src/memory/types.ts +146 -0
  73. package/packages/control/src/parity/surfaces.ts +748 -0
  74. package/packages/control/src/project.ts +141 -0
  75. package/packages/control/src/projection/local-ledger-view.ts +373 -0
  76. package/packages/control/src/projection/return-enforcement.ts +48 -0
  77. package/packages/control/src/projection/timeline-preview.ts +539 -0
  78. package/packages/control/src/projection/timeline.ts +708 -0
  79. package/packages/control/src/release/readiness.ts +831 -0
  80. package/packages/control/src/rubric/loader.ts +326 -0
  81. package/packages/control/src/rubric/promotion.ts +54 -0
  82. package/packages/control/src/rubric/runner.ts +159 -0
  83. package/packages/control/src/rubric/types.ts +158 -0
  84. package/packages/control/src/seat/owner-card.ts +388 -0
  85. package/packages/control/src/seat/readiness.ts +834 -0
  86. package/packages/control/src/session/runbook.ts +431 -0
  87. package/packages/control/src/shared/sanitize.ts +49 -0
  88. package/packages/control/src/supervision/action-classes.ts +192 -0
  89. package/packages/control/src/supervision/command-apply.ts +378 -0
  90. package/packages/control/src/supervision/errors.ts +14 -0
  91. package/packages/control/src/supervision/event-replay.ts +155 -0
  92. package/packages/control/src/supervision/events.ts +109 -0
  93. package/packages/control/src/supervision/index.ts +16 -0
  94. package/packages/control/src/supervision/manifest.ts +127 -0
  95. package/packages/control/src/supervision/paths.ts +49 -0
  96. package/packages/control/src/supervision/projection-adapter.ts +274 -0
  97. package/packages/control/src/supervision/projection.ts +75 -0
  98. package/packages/control/src/supervision/rebuild.ts +99 -0
  99. package/packages/control/src/supervision/session-open.ts +131 -0
  100. package/packages/control/src/supervision/session-read.ts +99 -0
  101. package/packages/control/src/supervision/sqlite-impl.ts +71 -0
  102. package/packages/control/src/supervision/sqlite.ts +121 -0
  103. package/packages/control/src/supervision/store-rows.ts +371 -0
  104. package/packages/control/src/supervision/turn-close.ts +154 -0
  105. package/packages/control/src/supervision/turn-open.ts +284 -0
  106. package/packages/control/src/sync/event-log-merge-driver.ts +263 -0
  107. package/packages/control/src/sync/join-plan.ts +375 -0
  108. package/packages/control/src/sync/outbox.ts +492 -0
  109. package/packages/control/src/workflow/evaluator.ts +140 -0
  110. package/packages/control/src/workflow/loader.ts +200 -0
  111. package/packages/control/src/workflow/types.ts +90 -0
  112. package/packages/control/src/workspace/authority.ts +499 -0
  113. package/packages/protocol/src/guards.ts +119 -0
  114. package/packages/protocol/src/huddle-board.ts +198 -0
  115. package/packages/protocol/src/huddle.ts +295 -0
  116. package/packages/protocol/src/incident.ts +251 -0
  117. package/packages/protocol/src/index.ts +8 -0
  118. package/packages/protocol/src/interfaces.ts +107 -0
  119. package/packages/protocol/src/packet-profile.ts +195 -0
  120. package/packages/protocol/src/state.ts +81 -0
  121. package/packages/protocol/src/types.ts +434 -0
  122. package/release/lineage.v0.json +14 -0
  123. package/scripts/release-candidate-verify.sh +175 -0
  124. package/scripts/release-checksum.sh +25 -0
  125. package/scripts/release-pack-canary.sh +97 -0
  126. package/scripts/release-scan.sh +249 -0
  127. package/scripts/release-sign.sh +34 -0
  128. package/templates/etiquette-vanilla-v0/README.md +2 -3
  129. package/templates/etiquette-vanilla-v0/source/control-seat/README.md +0 -6
  130. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +0 -5
  131. package/templates/etiquette-vanilla-v0/validate-vanilla.sh +0 -5
  132. package/templates/seat-packs-v0/README.md +3 -2
  133. package/templates/seat-packs-v0/source/claude-code-seat/README.md +3 -29
  134. package/templates/seat-packs-v0/source/codex-seat/README.md +3 -17
  135. package/templates/seat-packs-v0/source/gemini-seat/README.md +3 -23
  136. package/templates/seat-packs-v0/source/ollama-seat/README.md +3 -3
  137. package/templates/seat-packs-v0/source/openrouter-seat/README.md +3 -3
  138. package/docs/AGENT_SPAWNING.md +0 -78
  139. package/docs/INTEGRATION_UI.md +0 -215
  140. package/docs/OPERATOR_PLAYBOOK.md +0 -77
  141. package/docs/TAG_ROUTE.md +0 -95
  142. package/lib/etiquette-core.js +0 -315
  143. package/lib/etiquette.js +0 -1160
  144. package/templates/DISPATCH_PREMISES.md +0 -39
  145. package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +0 -55
  146. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +0 -39
  147. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +0 -53
  148. package/templates/hosted-receiver/README.md +0 -41
  149. package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +0 -129
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { parseArgs } from './cli/argv';
4
+ import { dispatchConsole, isConsoleCommand } from './cli/commands/console';
5
+ import { dispatchDispatch, isDispatchCommand } from './cli/commands/dispatch';
6
+ import { dispatchHarness, isHarnessCommand } from './cli/commands/harness';
7
+ import { dispatchHookCli, isHookCommand } from './cli/commands/hook';
8
+ import { dispatchLedger, isLedgerCommand } from './cli/commands/ledger';
9
+ import { dispatchLocalWorkflow, isLocalWorkflowCommand } from './cli/commands/local-workflow';
10
+ import { dispatchMemory, isMemoryCommand } from './cli/commands/memory';
11
+ import { dispatchRubric, isRubricCommand } from './cli/commands/rubric';
12
+ import { dispatchRelease, isReleaseCommand } from './cli/commands/release';
13
+ import { dispatchSeat, isSeatCommand } from './cli/commands/seat';
14
+ import { dispatchSession, isSessionCommand } from './cli/commands/session';
15
+ import { advancedUsage, usage } from './cli/usage';
16
+ import { dispatchSync, isSyncCommand } from './cli/commands/sync';
17
+ import { dispatchWorkflow, isWorkflowCommand } from './cli/commands/workflow';
18
+ import { dispatchWorkspace, isWorkspaceCommand } from './cli/commands/workspace';
19
+
20
+ /**
21
+ * Thin dispatcher. The former monolithic `cli.ts` was split across
22
+ * `cli/argv.ts` (parsing), `cli/usage.ts` (help text), and per-category
23
+ * command modules. This entry point only classifies the top-level command and
24
+ * delegates to the matching command module.
25
+ */
26
+ // Clean error rendering: a CLI failure must print a human-readable message,
27
+ // never a raw stack/bundle dump (see CONTRIBUTING.md). Set ETQ_DEBUG=1 for stacks.
28
+ function renderCliError(err: unknown): never {
29
+ const message = err instanceof Error ? err.message : String(err);
30
+ console.error(`error: ${message}`);
31
+ if (process.env.ETQ_DEBUG && err instanceof Error && err.stack) {
32
+ console.error(err.stack);
33
+ }
34
+ process.exit(1);
35
+ }
36
+ process.on('uncaughtException', renderCliError);
37
+ process.on('unhandledRejection', renderCliError);
38
+
39
+ const { positionals, flags } = parseArgs(process.argv.slice(2));
40
+ const command = positionals[0];
41
+
42
+ if (command === 'version' || flags.version) {
43
+ const { readFileSync } = await import('node:fs');
44
+ const pkg = JSON.parse(
45
+ readFileSync(new URL('../../../package.json', import.meta.url), 'utf-8'),
46
+ ) as { name?: string; version?: string };
47
+ console.log(`etiquette ${pkg.version ?? 'unknown'} (${pkg.name ?? 'etiquette'})`);
48
+ process.exit(0);
49
+ }
50
+
51
+ const SUPERVISION_COMMANDS_CLI: ReadonlySet<string> = new Set([
52
+ 'session-open',
53
+ 'session-status',
54
+ 'turn-open',
55
+ 'turn-close',
56
+ 'session-command',
57
+ 'session-project',
58
+ 'session-rebuild',
59
+ 'seat-validate',
60
+ ]);
61
+
62
+ if (!command) {
63
+ console.error(usage());
64
+ process.exit(1);
65
+ }
66
+
67
+ if (command === 'help' || flags.help) {
68
+ console.error(positionals[1] === 'advanced' ? advancedUsage() : usage());
69
+ process.exit(0);
70
+ }
71
+
72
+ if (SUPERVISION_COMMANDS_CLI.has(command)) {
73
+ const { dispatchSupervision } = await import('./cli/commands/supervision');
74
+ await dispatchSupervision(command, positionals, flags);
75
+ process.exit(0);
76
+ }
77
+
78
+ if (command === 'agent-plane') {
79
+ console.error(
80
+ 'agent-plane commands are not included in the local devkit; they return with the remote runner-plane work.',
81
+ );
82
+ process.exit(1);
83
+ }
84
+
85
+ if (isMemoryCommand(command)) {
86
+ await dispatchMemory(positionals, flags);
87
+ process.exit(0);
88
+ }
89
+
90
+ if (command === 'mcp') {
91
+ console.error(
92
+ 'mcp commands are not included in the local devkit; use a source workspace.',
93
+ );
94
+ process.exit(1);
95
+ }
96
+
97
+ if (command === 'parity') {
98
+ console.error(
99
+ 'parity commands are not included in the local devkit; use a source workspace.',
100
+ );
101
+ process.exit(1);
102
+ }
103
+
104
+ if (isConsoleCommand(command)) {
105
+ await dispatchConsole(positionals, flags);
106
+ process.exit(0);
107
+ }
108
+
109
+ if (isHookCommand(command)) {
110
+ await dispatchHookCli(positionals, flags);
111
+ process.exit(0);
112
+ }
113
+
114
+ if (isHarnessCommand(command)) {
115
+ await dispatchHarness(positionals, flags);
116
+ process.exit(0);
117
+ }
118
+
119
+ if (command === 'hosted') {
120
+ console.error(
121
+ 'hosted commands are not included in the local devkit; use a hosted/control-plane source workspace.',
122
+ );
123
+ process.exit(1);
124
+ }
125
+
126
+ if (command === 'integration') {
127
+ console.error(
128
+ 'integration commands are not included in the local devkit; use a source workspace.',
129
+ );
130
+ process.exit(1);
131
+ }
132
+
133
+ if (isLedgerCommand(command)) {
134
+ await dispatchLedger(positionals, flags);
135
+ process.exit(0);
136
+ }
137
+
138
+ if (command === 'linear') {
139
+ console.error(
140
+ 'linear commands are not included in the local devkit; use a source workspace.',
141
+ );
142
+ process.exit(1);
143
+ }
144
+
145
+ if (isDispatchCommand(command)) {
146
+ await dispatchDispatch(positionals, flags);
147
+ process.exit(0);
148
+ }
149
+
150
+ if (isRubricCommand(command)) {
151
+ await dispatchRubric(positionals, flags);
152
+ process.exit(0);
153
+ }
154
+
155
+ if (isReleaseCommand(command)) {
156
+ await dispatchRelease(positionals, flags);
157
+ process.exit(0);
158
+ }
159
+
160
+ if (command === 'remote') {
161
+ console.error(
162
+ 'remote commands are not included in the local devkit; remote execution ships with the hosted workspace product later.',
163
+ );
164
+ process.exit(1);
165
+ }
166
+
167
+ if (command === 'runtime') {
168
+ console.error(
169
+ 'runtime commands are not included in the local devkit; use an infra/runtime source workspace.',
170
+ );
171
+ process.exit(1);
172
+ }
173
+
174
+ if (isSeatCommand(command)) {
175
+ await dispatchSeat(positionals, flags);
176
+ process.exit(0);
177
+ }
178
+
179
+ if (isSessionCommand(command)) {
180
+ await dispatchSession(positionals, flags);
181
+ process.exit(0);
182
+ }
183
+
184
+ if (isSyncCommand(command)) {
185
+ await dispatchSync(positionals, flags);
186
+ process.exit(0);
187
+ }
188
+
189
+ if (isWorkflowCommand(command)) {
190
+ await dispatchWorkflow(positionals, flags);
191
+ process.exit(0);
192
+ }
193
+
194
+ if (isLocalWorkflowCommand(command)) {
195
+ await dispatchLocalWorkflow(positionals, flags);
196
+ process.exit(0);
197
+ }
198
+
199
+ if (isWorkspaceCommand(command)) {
200
+ await dispatchWorkspace(positionals, flags);
201
+ process.exit(0);
202
+ }
203
+
204
+ console.error(`unknown command: ${command}`);
205
+ console.error('');
206
+ console.error(usage());
207
+ process.exit(1);
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { parseArgs } from './cli/argv';
4
+ import { coreUsage } from './cli/core-usage';
5
+ import { dispatchCoreDispatch, isCoreDispatchCommand } from './cli/commands/dispatch-core';
6
+ import { dispatchLedger, isLedgerCommand } from './cli/commands/ledger';
7
+ import { dispatchRubric, isRubricCommand } from './cli/commands/rubric';
8
+ import { dispatchSeat, isSeatCommand } from './cli/commands/seat';
9
+ import { dispatchSession, isSessionCommand } from './cli/commands/session';
10
+ import { dispatchWorkflow, isWorkflowCommand } from './cli/commands/workflow';
11
+
12
+ const { positionals, flags } = parseArgs(process.argv.slice(2));
13
+ const command = positionals[0];
14
+
15
+ if (!command || command === 'help' || flags.help) {
16
+ console.error(coreUsage());
17
+ process.exit(command || flags.help ? 0 : 1);
18
+ }
19
+
20
+ if (isSeatCommand(command)) {
21
+ await dispatchSeat(positionals, flags);
22
+ process.exit(0);
23
+ }
24
+
25
+ if (isSessionCommand(command)) {
26
+ await dispatchSession(positionals, flags);
27
+ process.exit(0);
28
+ }
29
+
30
+ if (isWorkflowCommand(command)) {
31
+ await dispatchWorkflow(positionals, flags);
32
+ process.exit(0);
33
+ }
34
+
35
+ if (isRubricCommand(command)) {
36
+ await dispatchRubric(positionals, flags);
37
+ process.exit(0);
38
+ }
39
+
40
+ if (isCoreDispatchCommand(command)) {
41
+ await dispatchCoreDispatch(positionals, flags);
42
+ process.exit(0);
43
+ }
44
+
45
+ if (isLedgerCommand(command)) {
46
+ await dispatchLedger(positionals, flags);
47
+ process.exit(0);
48
+ }
49
+
50
+ throw new Error(`etiquette-core does not include '${command}'. Use the full 'etiquette' CLI for optional runtime, hosted, adapter, console, MCP, memory, sync, or release surfaces.`);
@@ -0,0 +1,202 @@
1
+ import type { SandboxRunReceipt } from '../rubric/types';
2
+ import type { SeatReadinessStatus } from '../seat/readiness';
3
+ import type { WorkflowCheckEnvelope, WorkflowCheckResult, WorkflowMode } from '../workflow/types';
4
+
5
+ export const OPERATIONAL_DECISIONS = [
6
+ 'dispatch_ready',
7
+ 'hold_for_grant',
8
+ 'blocked_by_capability',
9
+ 'blocked_by_validation',
10
+ 'quarantine_hold',
11
+ ] as const;
12
+
13
+ export type OperationalDecision = typeof OPERATIONAL_DECISIONS[number];
14
+
15
+ export interface OperationalDispatchDecision {
16
+ schema: 'operational-dispatch-decision.v0';
17
+ task_ref: string;
18
+ seat: string;
19
+ decision: OperationalDecision;
20
+ reasons: string[];
21
+ warnings: string[];
22
+ profile_hint: 'quarantine_hold' | 'batch_backlog' | 'sabbatical_improvement' | null;
23
+ inputs: {
24
+ seat_readiness: {
25
+ operational_status: SeatReadinessStatus['operational_status'];
26
+ routing_recommendation: SeatReadinessStatus['routing_recommendation'];
27
+ capability_trusted: boolean;
28
+ model_tier: SeatReadinessStatus['model_tier'];
29
+ effective_model_tier: SeatReadinessStatus['effective_model_tier'];
30
+ active_workers: number;
31
+ max_recommended_workers: number;
32
+ is_stale: boolean;
33
+ };
34
+ workflow_check: {
35
+ mode_id: string;
36
+ mode_type: WorkflowCheckResult['mode_type'];
37
+ recommendation: WorkflowCheckResult['recommendation'];
38
+ missing: string[];
39
+ warnings: string[];
40
+ };
41
+ strategy: {
42
+ requested_strategy: string | null;
43
+ policy: WorkflowMode['execution']['strategy_policy'];
44
+ supported: boolean | null;
45
+ unsupported: boolean | null;
46
+ };
47
+ rubric_receipt: {
48
+ receipt_id: string | null;
49
+ unexpected_outcomes: number | null;
50
+ accepted: boolean | null;
51
+ };
52
+ };
53
+ authority_boundary: {
54
+ can_dispatch: false;
55
+ can_authorize: false;
56
+ can_attach_grant: false;
57
+ can_execute: false;
58
+ consumer_is_engine: false;
59
+ };
60
+ }
61
+
62
+ function unique(values: string[]): string[] {
63
+ return [...new Set(values)];
64
+ }
65
+
66
+ function isGrantOnlyBlock(workflow: WorkflowCheckResult): boolean {
67
+ return workflow.missing.length > 0 && workflow.missing.every((item) => item === 'grant_ref');
68
+ }
69
+
70
+ function strategyStatus(
71
+ status: SeatReadinessStatus,
72
+ requestedStrategy: string | null,
73
+ ): { supported: boolean | null; unsupported: boolean | null } {
74
+ if (!requestedStrategy) return { supported: null, unsupported: null };
75
+ return {
76
+ supported: status.supported_strategies.includes(requestedStrategy),
77
+ unsupported: status.unsupported_strategies.includes(requestedStrategy),
78
+ };
79
+ }
80
+
81
+ function rubricAccepted(receipt: SandboxRunReceipt | null | undefined): boolean | null {
82
+ if (!receipt) return null;
83
+ return receipt.summary.unexpected_outcomes === 0;
84
+ }
85
+
86
+ export function evaluateOperationalDispatch(options: {
87
+ seat: SeatReadinessStatus;
88
+ mode: WorkflowMode;
89
+ envelope: WorkflowCheckEnvelope;
90
+ workflow: WorkflowCheckResult;
91
+ sandboxReceipt?: SandboxRunReceipt | null;
92
+ requestedStrategy?: string | null;
93
+ }): OperationalDispatchDecision {
94
+ const reasons: string[] = [];
95
+ const warnings: string[] = [...options.workflow.warnings];
96
+ let decision: OperationalDecision = 'dispatch_ready';
97
+ let profileHint: OperationalDispatchDecision['profile_hint'] = null;
98
+ const requestedStrategy = options.requestedStrategy ?? null;
99
+ const strategy = strategyStatus(options.seat, requestedStrategy);
100
+ const sandboxAccepted = rubricAccepted(options.sandboxReceipt);
101
+
102
+ if (options.envelope.advisory_consensus_claims_authority) {
103
+ decision = 'quarantine_hold';
104
+ profileHint = 'quarantine_hold';
105
+ reasons.push('advisory_consensus_claims_authority');
106
+ }
107
+
108
+ if (decision === 'dispatch_ready' && options.seat.routing_recommendation !== 'route_if_policy_allows') {
109
+ decision = 'blocked_by_capability';
110
+ reasons.push(`seat_routing_${options.seat.routing_recommendation}`);
111
+ }
112
+
113
+ if (decision === 'dispatch_ready' && options.seat.active_workers >= options.seat.max_recommended_workers) {
114
+ decision = 'blocked_by_capability';
115
+ reasons.push('seat_at_worker_capacity');
116
+ }
117
+
118
+ if (decision === 'dispatch_ready' && requestedStrategy && strategy.unsupported && options.mode.execution.strategy_policy === 'required') {
119
+ decision = 'blocked_by_capability';
120
+ reasons.push('required_strategy_unsupported');
121
+ } else if (requestedStrategy && strategy.unsupported) {
122
+ warnings.push('requested_strategy_unsupported_downshift_allowed');
123
+ }
124
+
125
+ if (decision === 'dispatch_ready' && options.workflow.recommendation === 'block') {
126
+ if (isGrantOnlyBlock(options.workflow)) {
127
+ decision = 'hold_for_grant';
128
+ reasons.push('grant_ref_required');
129
+ } else if (
130
+ options.workflow.missing.includes('validation_refs')
131
+ || options.workflow.missing.includes('receipt_ref')
132
+ ) {
133
+ decision = 'blocked_by_validation';
134
+ reasons.push(...options.workflow.missing.filter((item) => item === 'validation_refs' || item === 'receipt_ref'));
135
+ } else {
136
+ decision = 'quarantine_hold';
137
+ profileHint = 'quarantine_hold';
138
+ reasons.push(...options.workflow.missing);
139
+ }
140
+ }
141
+
142
+ if (decision === 'dispatch_ready' && options.mode.execution.rubric_required && !options.sandboxReceipt) {
143
+ decision = 'blocked_by_validation';
144
+ reasons.push('sandbox_run_receipt_required');
145
+ }
146
+
147
+ if (decision === 'dispatch_ready' && sandboxAccepted === false) {
148
+ decision = 'blocked_by_validation';
149
+ reasons.push('sandbox_run_receipt_unexpected_outcomes');
150
+ }
151
+
152
+ if (decision === 'dispatch_ready' && options.mode.mode_type === 'deliberative') {
153
+ profileHint = 'sabbatical_improvement';
154
+ }
155
+
156
+ return {
157
+ schema: 'operational-dispatch-decision.v0',
158
+ task_ref: options.envelope.task_ref,
159
+ seat: options.seat.seat,
160
+ decision,
161
+ reasons: unique(reasons),
162
+ warnings: unique(warnings),
163
+ profile_hint: profileHint,
164
+ inputs: {
165
+ seat_readiness: {
166
+ operational_status: options.seat.operational_status,
167
+ routing_recommendation: options.seat.routing_recommendation,
168
+ capability_trusted: options.seat.capability_trusted,
169
+ model_tier: options.seat.model_tier,
170
+ effective_model_tier: options.seat.effective_model_tier,
171
+ active_workers: options.seat.active_workers,
172
+ max_recommended_workers: options.seat.max_recommended_workers,
173
+ is_stale: options.seat.is_stale,
174
+ },
175
+ workflow_check: {
176
+ mode_id: options.workflow.mode_id,
177
+ mode_type: options.workflow.mode_type,
178
+ recommendation: options.workflow.recommendation,
179
+ missing: options.workflow.missing,
180
+ warnings: options.workflow.warnings,
181
+ },
182
+ strategy: {
183
+ requested_strategy: requestedStrategy,
184
+ policy: options.mode.execution.strategy_policy,
185
+ supported: strategy.supported,
186
+ unsupported: strategy.unsupported,
187
+ },
188
+ rubric_receipt: {
189
+ receipt_id: options.sandboxReceipt?.receipt_id ?? null,
190
+ unexpected_outcomes: options.sandboxReceipt?.summary.unexpected_outcomes ?? null,
191
+ accepted: sandboxAccepted,
192
+ },
193
+ },
194
+ authority_boundary: {
195
+ can_dispatch: false,
196
+ can_authorize: false,
197
+ can_attach_grant: false,
198
+ can_execute: false,
199
+ consumer_is_engine: false,
200
+ },
201
+ };
202
+ }