opencode-swarm 7.144.2 → 7.144.4

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/.opencode/skills/swarm-pr-review/SKILL.md +3 -1
  2. package/.opencode/skills/swarm-pr-review/references/lane-output-recoverability.md +124 -0
  3. package/.opencode/skills/swarm-pr-review/references/prompt-templates.md +2 -0
  4. package/README.md +3 -1
  5. package/dist/background/pending-delegations.d.ts +34 -0
  6. package/dist/cli/{config-doctor-7dfvxwjb.js → config-doctor-rw9zrjk6.js} +3 -3
  7. package/dist/cli/{core-dwmwdc4y.js → core-zjx9aqaf.js} +3 -3
  8. package/dist/cli/{curation-policy-pkb2eeb1.js → curation-policy-0wbrh11c.js} +5 -5
  9. package/dist/cli/curator-drift-2jbjv03a.js +1 -1
  10. package/dist/cli/{curator-w213v33y.js → curator-g54a7wv0.js} +33 -33
  11. package/dist/cli/{curator-llm-factory-rrs1q4hg.js → curator-llm-factory-xgb4pxmm.js} +33 -33
  12. package/dist/cli/{evidence-summary-service-t7n2h1he.js → evidence-summary-service-fnr5y54e.js} +14 -14
  13. package/dist/cli/{gate-evidence-xvxn603y.js → gate-evidence-2xt1x07r.js} +7 -7
  14. package/dist/cli/{guardrail-explain-v1mwsnkq.js → guardrail-explain-6wcgr9tz.js} +34 -34
  15. package/dist/cli/{guardrail-log-dn03dpz2.js → guardrail-log-5w4b9zrw.js} +4 -4
  16. package/dist/cli/{hive-promoter-asjtj7ga.js → hive-promoter-x63ehffd.js} +35 -35
  17. package/dist/cli/{index-ckrasab9.js → index-03pv47h2.js} +9 -9
  18. package/dist/cli/{index-4q9vfav6.js → index-1csyxv0f.js} +1 -1
  19. package/dist/cli/{index-s2rcz51a.js → index-1jsmmx7y.js} +66 -34
  20. package/dist/cli/{index-jsfghpy2.js → index-2m7mavaz.js} +2 -2
  21. package/dist/cli/{index-p3tnmkvc.js → index-4w5qdbk7.js} +12 -12
  22. package/dist/cli/{index-dhh2j2nd.js → index-8j0va7jp.js} +2 -2
  23. package/dist/cli/{index-y95nwsge.js → index-9qq7c18c.js} +1 -1
  24. package/dist/cli/{index-qpt8ahph.js → index-az8etqpp.js} +12 -12
  25. package/dist/cli/{index-gdd4jt6b.js → index-bt9aa01f.js} +1 -1
  26. package/dist/cli/{index-333kvewd.js → index-btmsqv7p.js} +4 -4
  27. package/dist/cli/{index-d55crzd4.js → index-cz25e8xp.js} +7 -7
  28. package/dist/cli/{index-g2ajae1z.js → index-d12jd5mn.js} +2 -2
  29. package/dist/cli/{index-tq5s07ta.js → index-dty5qgk2.js} +1 -1
  30. package/dist/cli/{index-k31en0ja.js → index-f9vvg5xb.js} +3 -3
  31. package/dist/cli/{index-k92cagmt.js → index-fqcjragy.js} +2 -2
  32. package/dist/cli/{index-jb4tchvy.js → index-h98t1m88.js} +2 -2
  33. package/dist/cli/{index-4fda8kkw.js → index-jabkn643.js} +30 -5
  34. package/dist/cli/{index-erfnw81g.js → index-mazgg5s2.js} +1 -1
  35. package/dist/cli/{index-m6wv2qdr.js → index-nckg4gxb.js} +2 -2
  36. package/dist/cli/{index-tg9fn2dy.js → index-p7cm3gtj.js} +38 -36
  37. package/dist/cli/{index-dg2w0wr4.js → index-psvxq93b.js} +3 -3
  38. package/dist/cli/{index-zr370283.js → index-pw83zgny.js} +3 -3
  39. package/dist/cli/{index-nretd4qn.js → index-q4ed1jk7.js} +1539 -963
  40. package/dist/cli/{index-hqvt3mhk.js → index-q67jb94n.js} +1 -1
  41. package/dist/cli/{index-whezv7vc.js → index-v3y3qg48.js} +1 -1
  42. package/dist/cli/{index-av0f6mm0.js → index-x6tp0hfr.js} +9 -9
  43. package/dist/cli/{index-h3z64mhz.js → index-y8j8ehc8.js} +2 -2
  44. package/dist/cli/{index-ne8cfgw5.js → index-yts89pqg.js} +4 -4
  45. package/dist/cli/{index-w7x7qxz2.js → index-ywn7vtxp.js} +1 -1
  46. package/dist/cli/{index-g1c5fgaw.js → index-z6v7kwpa.js} +4 -4
  47. package/dist/cli/{index-7ca3a6gj.js → index-zb0xcz9t.js} +10 -10
  48. package/dist/cli/index.js +34 -34
  49. package/dist/cli/{knowledge-escalator-cg19dhe5.js → knowledge-escalator-ypg14d5r.js} +13 -13
  50. package/dist/cli/{knowledge-events-yzvysaqd.js → knowledge-events-nkrym4wb.js} +11 -11
  51. package/dist/cli/{knowledge-link-fn5j3r4q.js → knowledge-link-e4qgqmpx.js} +4 -4
  52. package/dist/cli/{knowledge-store-6f77xpmm.js → knowledge-store-vh3nhtg2.js} +6 -6
  53. package/dist/cli/{knowledge-validator-4b28zdxa.js → knowledge-validator-jrxvexv6.js} +8 -8
  54. package/dist/cli/{pending-delegations-thy8g30k.js → pending-delegations-pw79c8ds.js} +3 -3
  55. package/dist/cli/{pr-subscriptions-jyav582d.js → pr-subscriptions-fk628bhc.js} +3 -3
  56. package/dist/cli/{runner-pde6b5sx.js → runner-b02sz2vx.js} +5 -5
  57. package/dist/cli/{scan-cursor-nqbb1xt6.js → scan-cursor-fp7w5jmc.js} +7 -7
  58. package/dist/cli/{schema-jj2pb6zp.js → schema-rptwqbm4.js} +2 -2
  59. package/dist/cli/{scope-persistence-63nasq0z.js → scope-persistence-0bkaxawa.js} +7 -7
  60. package/dist/cli/{skill-generator-nsymtdqm.js → skill-generator-nh8b4gjv.js} +16 -16
  61. package/dist/cli/{telemetry-xyfb5vm8.js → telemetry-cybx6cfz.js} +1 -1
  62. package/dist/cli/{worktree-collision-ownership-j6d33p49.js → worktree-collision-ownership-hqd9ypsz.js} +6 -6
  63. package/dist/cli/{worktree-isolation-g54kxw6x.js → worktree-isolation-canf3rj8.js} +33 -33
  64. package/dist/commands/index.d.ts +1 -0
  65. package/dist/commands/recover.d.ts +17 -0
  66. package/dist/commands/registry.d.ts +10 -2
  67. package/dist/commands/reset-session.d.ts +2 -0
  68. package/dist/hooks/context-budget.d.ts +4 -0
  69. package/dist/hooks/context-usage.d.ts +48 -0
  70. package/dist/hooks/pr-workflow-gate.d.ts +160 -4
  71. package/dist/index.js +556 -550
  72. package/dist/observability/catalog.d.ts +8 -6
  73. package/dist/sast/semgrep.d.ts +3 -2
  74. package/dist/telemetry.d.ts +17 -1
  75. package/dist/tools/context-status.d.ts +9 -3
  76. package/dist/tools/dispatch-lanes.d.ts +27 -2
  77. package/dist/tools/pre-check-batch.d.ts +9 -0
  78. package/dist/tools/sast-scan.d.ts +3 -0
  79. package/dist/workflow/coder-settlement.d.ts +74 -0
  80. package/package.json +1 -1
@@ -20,60 +20,60 @@ import {
20
20
  sanitizeWorktreeTaskId,
21
21
  standardWorktreeByCallID,
22
22
  standardWorktreeSerializationSessions
23
- } from "./index-nretd4qn.js";
24
- import"./index-g2ajae1z.js";
25
- import"./index-jb4tchvy.js";
26
- import"./index-qpt8ahph.js";
23
+ } from "./index-q4ed1jk7.js";
24
+ import"./index-d12jd5mn.js";
25
+ import"./index-h98t1m88.js";
26
+ import"./index-az8etqpp.js";
27
27
  import"./index-134d35c1.js";
28
28
  import"./index-b6e016tv.js";
29
- import"./index-4q9vfav6.js";
30
- import"./index-k92cagmt.js";
29
+ import"./index-1csyxv0f.js";
30
+ import"./index-fqcjragy.js";
31
31
  import"./index-y8552snf.js";
32
- import"./index-m6wv2qdr.js";
32
+ import"./index-nckg4gxb.js";
33
33
  import"./index-70ha9e09.js";
34
34
  import"./index-c8s9a3zh.js";
35
35
  import"./index-9ss2m4rs.js";
36
- import"./index-d55crzd4.js";
37
36
  import"./index-74hpm6sh.js";
38
- import"./index-7ca3a6gj.js";
39
- import"./index-av0f6mm0.js";
40
- import"./index-zr370283.js";
41
- import"./index-g1c5fgaw.js";
42
- import"./index-556ja8an.js";
43
- import"./index-gdd4jt6b.js";
37
+ import"./index-bt9aa01f.js";
38
+ import"./index-zb0xcz9t.js";
39
+ import"./index-x6tp0hfr.js";
40
+ import"./index-yts89pqg.js";
41
+ import"./index-dty5qgk2.js";
42
+ import"./index-rtry5xyf.js";
44
43
  import"./index-zsrtt42s.js";
44
+ import"./index-jabkn643.js";
45
45
  import"./index-k3cxyk66.js";
46
- import"./index-4fda8kkw.js";
47
- import"./index-dhh2j2nd.js";
48
- import"./index-8fwhhayc.js";
49
- import"./index-q1exe2b3.js";
46
+ import"./index-cz25e8xp.js";
47
+ import"./index-8j0va7jp.js";
48
+ import"./index-pw83zgny.js";
49
+ import"./index-z6v7kwpa.js";
50
+ import"./index-556ja8an.js";
50
51
  import"./index-7sy3aa9m.js";
51
52
  import"./index-wx8zdh4a.js";
52
- import"./index-p3tnmkvc.js";
53
+ import"./index-8fwhhayc.js";
54
+ import"./index-q1exe2b3.js";
55
+ import"./index-03pv47h2.js";
56
+ import"./index-4w5qdbk7.js";
53
57
  import {
54
58
  resolveWorktreeIsolationConfig
55
- } from "./index-dg2w0wr4.js";
59
+ } from "./index-psvxq93b.js";
56
60
  import"./index-gprxjmm7.js";
57
61
  import"./index-n832052r.js";
58
- import"./index-y95nwsge.js";
59
- import"./index-h3z64mhz.js";
60
62
  import"./index-rn0eq85g.js";
61
- import"./index-4rhhvd1a.js";
62
- import"./index-whezv7vc.js";
63
63
  import"./index-z6xqpmqg.js";
64
+ import"./index-9qq7c18c.js";
65
+ import"./index-y8j8ehc8.js";
66
+ import"./index-4rhhvd1a.js";
67
+ import"./index-v3y3qg48.js";
64
68
  import"./index-zjygnfay.js";
65
- import"./index-ne8cfgw5.js";
66
- import"./index-tq5s07ta.js";
67
- import"./index-rtry5xyf.js";
68
- import"./index-ckrasab9.js";
69
69
  import"./index-ae75rja9.js";
70
- import"./index-w7x7qxz2.js";
71
- import"./index-erfnw81g.js";
72
- import"./index-bk5tah7q.js";
70
+ import"./index-ywn7vtxp.js";
71
+ import"./index-mazgg5s2.js";
73
72
  import"./index-ed5ykebp.js";
74
- import"./index-k31en0ja.js";
73
+ import"./index-bk5tah7q.js";
74
+ import"./index-f9vvg5xb.js";
75
+ import"./index-1jsmmx7y.js";
75
76
  import"./index-7g4c7s5r.js";
76
- import"./index-s2rcz51a.js";
77
77
  import"./index-bpmtbmy9.js";
78
78
  import"./index-4nt52yr9.js";
79
79
  import"./index-zgwm4ryv.js";
@@ -46,6 +46,7 @@ export { handlePlanCommand } from './plan';
46
46
  export { handlePreflightCommand } from './preflight';
47
47
  export { handlePromoteCommand } from './promote';
48
48
  export { handleQaGatesCommand } from './qa-gates';
49
+ export { handleRecoverCommand } from './recover';
49
50
  export { handleHelpCommand } from './registry';
50
51
  export type { CommandContext, CommandEntry, RegisteredCommand, } from './registry.js';
51
52
  export { COMMAND_REGISTRY, resolveCommand, VALID_COMMANDS, } from './registry.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Handles the /swarm recover command (issue #2268).
3
+ *
4
+ * The user-facing invoker for coder-settlement recovery. The wedge class this
5
+ * exists for: a DISPATCHED settlement WAL whose completion (toolAfter) never
6
+ * arrived — every dispatch retry is refused with CODER_SETTLEMENT_IN_PROGRESS
7
+ * / CODER_DISPATCH_IN_PROGRESS and internal sinks (update_task_status, /swarm
8
+ * close) are paused too. Safe mode recovers settlements whose owning process
9
+ * is gone; --force additionally releases ownership keys still held by THIS
10
+ * process (an operator assertion that no dispatch is genuinely in flight —
11
+ * a still-running dispatch's late completion will then fail settlement with
12
+ * CODER_SETTLEMENT_IDEMPOTENCY_CONFLICT, which is safe to ignore).
13
+ *
14
+ * Human-only by policy: agents already self-heal dead-owner settlements via
15
+ * update_task_status, and --force must stay an operator decision.
16
+ */
17
+ export declare function handleRecoverCommand(directory: string, args: string[]): Promise<string>;
@@ -619,7 +619,7 @@ export declare const COMMAND_REGISTRY: {
619
619
  readonly handler: (ctx: CommandContext) => Promise<string>;
620
620
  readonly description: "Clear a stuck PR_REVIEW/PR_FEEDBACK mechanical gate and stop the auto-resume loop [mode] [reason]";
621
621
  readonly args: "[PR_REVIEW|PR_FEEDBACK] [reason...]";
622
- readonly details: "Human-only escape hatch for an unrecoverable PR_REVIEW or PR_FEEDBACK mechanical gate. When the architect cannot reach complete_pr_workflow — for example a compound `git fetch && git checkout` was rejected as read-only shell syntax, the PR head cannot be fetched, or the working tree is on the wrong branch — running this clears the durable gate state for the current session and stops the auto-resume loop without depending on the trapped model. The agent itself cannot run this command; it must call the abort_pr_workflow tool (or ask you to run this command). Both paths funnel into the same fail-closed abortPrWorkflow hook, which refuses while the workflow is armed for publication or while PR workflow lanes are still in flight. When checkout preparation preserved a stash, the result instructs the caller to run prepare_pr_workflow_checkout operation=restore after the clear. An audit event is appended to .swarm/events.jsonl.";
622
+ readonly details: "Human-only escape hatch for an unrecoverable PR_REVIEW or PR_FEEDBACK mechanical gate. When the architect cannot reach complete_pr_workflow — for example a compound `git fetch && git checkout` was rejected as read-only shell syntax, the PR head cannot be fetched, or the working tree is on the wrong branch — running this clears the durable gate state for the current session and stops the auto-resume loop without depending on the trapped model. The agent itself cannot run this command; it must call the abort_pr_workflow tool (or ask you to run this command). Both paths funnel into the same fail-closed abortPrWorkflow hook, which refuses while the workflow is armed for publication or while PR workflow lanes are still in flight. This human-only force path has exactly one exception to that second refusal (issue #2251): when the ONLY lanes still blocking are ones past the 30-minute staleness horizon that the liveness probe reports as still running — a lane nothing will ever settle on a schedule — it clears the gate anyway, names exactly which lanes it overrode, and finalizes their delegation records so the session can start a new PR workflow. Those sessions are NOT stopped and their output is NOT collected. A lane with a fresh updatedAt still blocks even under force, and any delegation record that still keeps the session blocked is named in the warning. When checkout preparation preserved a stash, the result instructs the caller to run prepare_pr_workflow_checkout operation=restore after the clear. An audit event is appended to .swarm/events.jsonl.";
623
623
  readonly category: "utility";
624
624
  readonly toolPolicy: "restricted";
625
625
  };
@@ -825,11 +825,19 @@ export declare const COMMAND_REGISTRY: {
825
825
  readonly 'reset-session': {
826
826
  readonly handler: (ctx: CommandContext) => Promise<string>;
827
827
  readonly description: "Clear session state while preserving plan, evidence, and knowledge";
828
- readonly details: "Deletes only .swarm/session/state.json and any other session files. Clears in-memory agent sessions, delegation chains, and active-agent mappings. Preserves plan, evidence, and knowledge for cross-session continuity. Before deleting, auto-backs up the session files it removes to .swarm/reset-backups/<timestamp>/ (newest 5 kept).";
828
+ readonly details: "Deletes only .swarm/session/state.json and any other session files. Clears in-memory agent sessions, delegation chains, and active-agent mappings. Preserves plan, evidence, and knowledge for cross-session continuity. Also recovers stale coder settlements, releasing in-flight ownership held by this process, so dispatches cannot stay wedged on CODER_DISPATCH_IN_PROGRESS (issue #2268). Before deleting, auto-backs up the session files it removes to .swarm/reset-backups/<timestamp>/ (newest 5 kept).";
829
829
  readonly args: "";
830
830
  readonly category: "utility";
831
831
  readonly toolPolicy: "restricted";
832
832
  };
833
+ readonly recover: {
834
+ readonly handler: (ctx: CommandContext) => Promise<string>;
835
+ readonly description: "Recover wedged coder settlements [task_id] [--force]";
836
+ readonly details: "Settles stale coder-settlement WALs in .swarm/coder-settlements/ — the CODER_DISPATCH_IN_PROGRESS wedge where a dispatch's completion never fired (issue #2268). Safe mode recovers settlements whose owner process is gone. --force also releases ownership keys held by this process: use only when no dispatch is genuinely running (a late completion then reports CODER_SETTLEMENT_IDEMPOTENCY_CONFLICT, safe to ignore). Never interrupts another live OpenCode process. Human-only.";
837
+ readonly args: "[task_id] [--force]";
838
+ readonly category: "utility";
839
+ readonly toolPolicy: "human-only";
840
+ };
833
841
  readonly rollback: {
834
842
  readonly handler: (ctx: CommandContext) => Promise<string>;
835
843
  readonly description: "Restore swarm state or project files to a checkpoint";
@@ -1,3 +1,4 @@
1
+ import { recoverStaleCoderSettlements } from '../workflow/coder-settlement.js';
1
2
  import { type OrphanCleanupResult } from '../worktree/merge';
2
3
  import { type ResetBackupResult } from './reset-backup';
3
4
  /**
@@ -9,6 +10,7 @@ import { type ResetBackupResult } from './reset-backup';
9
10
  export declare const _internals: {
10
11
  cleanupOrphanedBranches: (directory: string, activeSessionIds: string[]) => Promise<OrphanCleanupResult>;
11
12
  backupSwarmStateBeforeReset: (directory: string, kind: 'reset' | 'reset-session', relEntries: string[]) => ResetBackupResult;
13
+ recoverStaleCoderSettlements: typeof recoverStaleCoderSettlements;
12
14
  };
13
15
  /**
14
16
  * Handles the /swarm reset-session command.
@@ -6,6 +6,7 @@
6
6
  * to provide proactive context management guidance to the architect agent.
7
7
  */
8
8
  import type { PluginConfig } from '../config';
9
+ import { telemetry } from '../telemetry';
9
10
  interface MessageInfo {
10
11
  role: string;
11
12
  agent?: string;
@@ -31,6 +32,9 @@ interface MessageWithParts {
31
32
  info: MessageInfo;
32
33
  parts: MessagePart[];
33
34
  }
35
+ export declare const _internals: {
36
+ telemetryContextPruned: typeof telemetry.contextPruned;
37
+ };
34
38
  /**
35
39
  * Creates the experimental.chat.messages.transform hook for context budget tracking.
36
40
  * Injects warnings when context usage exceeds configured thresholds.
@@ -0,0 +1,48 @@
1
+ export interface ContextUsageMessageInfo {
2
+ role?: string;
3
+ tokens?: {
4
+ input?: unknown;
5
+ cache?: {
6
+ read?: unknown;
7
+ write?: unknown;
8
+ };
9
+ };
10
+ [key: string]: unknown;
11
+ }
12
+ export interface ContextUsageMessagePart {
13
+ type?: string;
14
+ text?: string;
15
+ state?: {
16
+ status?: string;
17
+ input?: unknown;
18
+ output?: string;
19
+ error?: string;
20
+ [key: string]: unknown;
21
+ };
22
+ [key: string]: unknown;
23
+ }
24
+ export interface ContextUsageMessage {
25
+ info?: ContextUsageMessageInfo;
26
+ parts?: ContextUsageMessagePart[];
27
+ }
28
+ export type ContextUsageSource = 'provider' | 'estimated';
29
+ export interface ContextUsageResult {
30
+ tokensUsed: number;
31
+ source: ContextUsageSource;
32
+ assistantAnchorIndex: number | null;
33
+ }
34
+ export declare function serializeToolInput(input: unknown): string;
35
+ export declare function estimateToolInputTokens(input: unknown): number;
36
+ export declare function getVisibleToolPartText(part: ContextUsageMessagePart): string;
37
+ export declare function estimateVisibleToolPartTokens(part: ContextUsageMessagePart): number;
38
+ export declare function estimateMessageTokens(message: ContextUsageMessage): number;
39
+ export declare function readProviderPromptTokens(message: ContextUsageMessage | undefined): number | undefined;
40
+ export declare function computeContextUsage(messages: ContextUsageMessage[] | undefined): ContextUsageResult;
41
+ export declare const _test_exports: {
42
+ computeContextUsage: typeof computeContextUsage;
43
+ estimateToolInputTokens: typeof estimateToolInputTokens;
44
+ estimateVisibleToolPartTokens: typeof estimateVisibleToolPartTokens;
45
+ estimateMessageTokens: typeof estimateMessageTokens;
46
+ readProviderPromptTokens: typeof readProviderPromptTokens;
47
+ serializeToolInput: typeof serializeToolInput;
48
+ };
@@ -2,7 +2,7 @@ import * as fsp from 'node:fs/promises';
2
2
  import { z } from 'zod';
3
3
  import { type CandidateSeverity, type RowFormatFamily } from '../background/candidate-contract.js';
4
4
  import { type LaneOutputArtifact } from '../background/lane-output-store.js';
5
- import { type BackgroundDelegationRecord, type BackgroundDelegationResult, findByBatchId } from '../background/pending-delegations.js';
5
+ import { type BackgroundDelegationRecord, type BackgroundDelegationResult, type BackgroundDelegationWorkflowLaneRecovery, findByBatchId, sweepStaleDelegations } from '../background/pending-delegations.js';
6
6
  import { type PrReviewInlineTriggerRow } from '../background/pr-review-trigger-contract.js';
7
7
  import { type RevisionDigestResult, resolveCommitCountSince, resolveCommitCountSinceAsync, resolveCurrentGitHead, resolveCurrentGitHeadAsync, resolveCurrentUpstreamPushTarget, resolveCurrentUpstreamPushTargetAsync, resolveCurrentUpstreamRemoteRef, resolveExactRemoteBranchHead, resolveExactRemoteBranchHeadAsync, resolveIsExactSingleChildCommit, resolveIsExactSingleChildCommitAsync, resolveIsWorkingTreeClean, resolveIsWorkingTreeCleanAsync, resolvePrReviewDiffStats, resolvePrReviewDiffStatsAsync, resolvePrWorkflowRevisionDigest, resolvePrWorkflowRevisionDigestDetailed, resolveRemoteRefsContainingHead, resolveRemoteRefsContainingHeadAsync } from '../background/workspace-snapshot.js';
8
8
  import { classifyPrWorkflowGitState, type PrWorkflowGitState } from '../git/pr-workflow-state.js';
@@ -10,7 +10,7 @@ export declare const PR_REVIEW_BASE_DIMENSION_IDS: readonly ["intent-architectur
10
10
  export declare const PR_REVIEW_REQUIRED_MICRO_LANE_IDS: ("auth-identity-secrets" | "untrusted-input-boundaries" | "subprocess-platform" | "concurrency-state" | "dependencies-build-release" | "api-schema-migrations" | "test-infrastructure" | "ui-accessibility-i18n" | "privacy-observability" | "generated-provenance" | "unclassified-risk")[];
11
11
  export type PrReviewBaseDimensionId = (typeof PR_REVIEW_BASE_DIMENSION_IDS)[number];
12
12
  export type PrWorkflowMode = 'PR_REVIEW' | 'PR_FEEDBACK';
13
- export type PrReviewLaneValidationPredicate = 'batch.validated_at' | 'batch.expected_lane_unique' | 'record.missing' | 'record.duplicate_lane' | 'record.subagent_session_id' | 'record.duplicate_subagent_session_id' | 'record.forbidden_subagent_session_id' | 'record.created_at' | 'record.workflow_lane' | 'record.owned_workflow_lanes' | 'record.mode' | 'record.pr_head_sha' | 'record.git_head' | 'record.status' | 'result.output_degraded' | 'result.transcript_incomplete' | 'result.truncated' | 'result.chars' | 'result.digest' | 'result.output_ref' | 'artifact.readable' | 'artifact.ref' | 'artifact.batch_id' | 'artifact.lane_id' | 'artifact.mode' | 'artifact.session_id' | 'artifact.parent_session_id' | 'artifact.agent' | 'artifact.role' | 'artifact.source' | 'artifact.workflow_lane_record' | 'artifact.workflow_lane_expected' | 'artifact.pr_head_sha' | 'artifact.git_head' | 'artifact.revision_digest' | 'record.scope' | 'artifact.scope' | 'artifact.digest' | 'artifact.chars' | 'discovery.header' | 'discovery.row' | 'discovery.coverage' | 'discovery.duplicate_evidence';
13
+ export type PrReviewLaneValidationPredicate = 'batch.validated_at' | 'batch.expected_lane_unique' | 'record.missing' | 'record.duplicate_lane' | 'record.subagent_session_id' | 'record.duplicate_subagent_session_id' | 'record.forbidden_subagent_session_id' | 'record.created_at' | 'record.workflow_lane' | 'record.owned_workflow_lanes' | 'record.mode' | 'record.pr_head_sha' | 'record.git_head' | 'record.status' | 'result.output_degraded' | 'result.transcript_incomplete' | 'result.chars' | 'result.digest' | 'result.output_ref' | 'artifact.readable' | 'artifact.ref' | 'artifact.batch_id' | 'artifact.lane_id' | 'artifact.mode' | 'artifact.session_id' | 'artifact.parent_session_id' | 'artifact.agent' | 'artifact.role' | 'artifact.source' | 'artifact.workflow_lane_record' | 'artifact.workflow_lane_expected' | 'artifact.pr_head_sha' | 'artifact.git_head' | 'artifact.revision_digest' | 'record.scope' | 'artifact.scope' | 'artifact.digest' | 'artifact.chars' | 'discovery.header' | 'discovery.row' | 'discovery.coverage' | 'discovery.duplicate_evidence';
14
14
  export interface PrReviewLaneValidationFailure {
15
15
  predicate: PrReviewLaneValidationPredicate;
16
16
  expected: string;
@@ -25,6 +25,8 @@ export type PrReviewLaneValidationResult = {
25
25
  * distinguishable from a well-formed one.
26
26
  */
27
27
  salvaged?: readonly string[];
28
+ /** Typed recovery disclosures persisted to the durable delegation ledger. */
29
+ recoveries?: readonly BackgroundDelegationWorkflowLaneRecovery[];
28
30
  } | {
29
31
  ok: false;
30
32
  failure: PrReviewLaneValidationFailure;
@@ -44,6 +46,20 @@ export interface PrReviewDiscoveryLaneValidationInput {
44
46
  checkWorkflowLane?: boolean;
45
47
  };
46
48
  }
49
+ export interface PrWorkflowTransportRecoveryValidationInput {
50
+ directory: string;
51
+ record: BackgroundDelegationRecord;
52
+ result: BackgroundDelegationResult;
53
+ artifact: LaneOutputArtifact | null;
54
+ revisionDigest: string;
55
+ }
56
+ export type PrWorkflowTransportRecoveryValidationResult = {
57
+ ok: true;
58
+ recoveries?: readonly BackgroundDelegationWorkflowLaneRecovery[];
59
+ } | {
60
+ ok: false;
61
+ reason: string;
62
+ };
47
63
  export interface PrWorkflowCheckoutRecoveryRecord {
48
64
  code: 'UNMERGED_INDEX' | 'GIT_OPERATION_IN_PROGRESS' | 'DIRTY_SUBMODULE' | 'SWARM_STATE_TRACKING_ERROR' | 'GIT_STATE_INDETERMINATE';
49
65
  retryable: false;
@@ -408,13 +424,99 @@ export declare function withInactivePrWorkflowCheckoutRestoreLock<T>(directory:
408
424
  export declare function clearPrWorkflowGateState(directory: string, sessionID: string, expectedRevision?: number, options?: {
409
425
  allowSalvagedRead?: boolean;
410
426
  }): Promise<void>;
427
+ /**
428
+ * The single session operation the liveness probe needs.
429
+ *
430
+ * Deliberately a narrow LOCAL structural type rather than a type-only import of
431
+ * `SessionOps` from `src/tools/dispatch-lanes.ts`: that module's
432
+ * `isLaneReadyForCollection` is the fail-CLOSED counterpart of this probe, and
433
+ * keeping the two textually independent removes any invitation to "share" the
434
+ * predicate. A type-only import would be erased either way; this is about
435
+ * preventing the wrong reuse, not about module graph cost.
436
+ */
437
+ interface PrWorkflowLaneLivenessSessionOps {
438
+ status?: (args: {
439
+ query?: {
440
+ directory?: string;
441
+ };
442
+ }) => Promise<{
443
+ data?: Record<string, {
444
+ type?: string;
445
+ }> | null;
446
+ error?: unknown;
447
+ }>;
448
+ }
449
+ /** Why a probe produced no evidence of life. Absent means the probe ran. */
450
+ export type PrWorkflowLaneProbeDegradedReason = 'probe-unavailable' | 'probe-error' | 'probe-timeout' | 'probe-no-data';
451
+ /**
452
+ * Probe which of `records` have a session the host affirmatively reports as
453
+ * still running (issue #2251).
454
+ *
455
+ * **FAIL-OPEN, by design.** For its ERROR and NO-DATA cases this is the exact
456
+ * inverse of `isLaneReadyForCollection` (`src/tools/dispatch-lanes.ts`), which
457
+ * returns `false` on a truthy `error`, on missing `data`, and on a throw —
458
+ * because a lane it cannot verify must not be collected. The two agree, rather
459
+ * than invert, on ONE case: a host that exposes no `status` function at all.
460
+ * There the collector returns `true` (`dispatch-lanes.ts`, the `typeof
461
+ * session.status !== 'function'` guard) and this probe reports
462
+ * `probe-unavailable`, so both fall through to proceeding — an unprobeable host
463
+ * must not wedge either side.
464
+ *
465
+ * Here the default outcome must be "settle": an unavailable, erroring,
466
+ * timing-out or empty probe returns the empty set, so age alone decides and the
467
+ * reachability floor this whole subsystem exists to preserve is untouched. Only
468
+ * a probe that RAN and affirmatively named a live session may contradict
469
+ * staleness.
470
+ *
471
+ * The returned set is built only from a fully-read response — a mid-iteration
472
+ * throw yields the empty set rather than a partial spare list, so a malformed
473
+ * response can never spare an arbitrary subset of lanes.
474
+ *
475
+ * Keys are `subagentSessionId`s. A record without one is unprobeable and is
476
+ * simply never added (it settles), which is the fail-open direction.
477
+ */
478
+ declare function probeAlivePrWorkflowLaneSessions(directory: string, records: BackgroundDelegationRecord[]): Promise<{
479
+ alive: Set<string>;
480
+ degradedReason?: PrWorkflowLaneProbeDegradedReason;
481
+ }>;
411
482
  export interface PrWorkflowStaleLaneSettlement {
412
- /** Lanes still genuinely in flight (fresh `updatedAt`). These still block. */
483
+ /**
484
+ * Every lane that still blocks: lanes with a fresh `updatedAt` PLUS lanes
485
+ * past the horizon whose session the liveness probe reported still running.
486
+ */
413
487
  openLaneIds: string[];
414
488
  openLanes: number;
489
+ /**
490
+ * Open lanes that block on FRESHNESS alone (age below the horizon).
491
+ *
492
+ * Separated from `openLanes` because the human-only `force` abort override
493
+ * (issue #2251 S3) must distinguish "blocked only by probe retention", which
494
+ * an operator may override, from "blocked by a lane that is genuinely young",
495
+ * which stays fail-closed. Deriving it by subtraction or by comparing lane
496
+ * LABELS would be wrong: `prWorkflowLaneLabel` falls back to `'unknown'`, so
497
+ * labels are not unique.
498
+ */
499
+ freshOpenLanes: number;
415
500
  /** Lanes stale past the horizon, treated as settled with disclosure. */
416
501
  presumedStaleLaneIds: string[];
417
- /** Operator-facing disclosure; `undefined` when nothing was presumed stale. */
502
+ /**
503
+ * Lanes past the horizon that the probe spared. Present only when non-empty.
504
+ */
505
+ probedAliveLaneIds?: string[];
506
+ /**
507
+ * The SAME records as {@link probedAliveLaneIds}, in the same order, keyed by
508
+ * `correlationId` instead of by display label.
509
+ *
510
+ * Both are needed and neither substitutes for the other: `prWorkflowLaneLabel`
511
+ * falls back to `'unknown'` and is not unique, so it cannot address a durable
512
+ * record — while `correlationId` is the ledger's primary key and is what the
513
+ * human-only `force` override must name to finalize exactly these records and
514
+ * nothing else. Present only when non-empty.
515
+ */
516
+ probeRetainedCorrelationIds?: string[];
517
+ /** Set when the probe could not produce evidence; absent when it ran. */
518
+ probeDegradedReason?: PrWorkflowLaneProbeDegradedReason;
519
+ /** Operator-facing disclosure; `undefined` when nothing was settled or retained. */
418
520
  disclosure?: string;
419
521
  }
420
522
  /**
@@ -439,6 +541,13 @@ export interface PrWorkflowStaleLaneSettlement {
439
541
  *
440
542
  * A lane with a RECENT `updatedAt` still blocks: a re-verification that CAN run
441
543
  * and reports "still progressing" contradicts settlement and fails closed.
544
+ *
545
+ * Issue #2251 adds the second, stronger contradiction: a lane PAST the horizon
546
+ * whose session the host affirmatively reports as `busy`/`retry` is genuinely
547
+ * running (nothing heartbeats `updatedAt`, so age alone cannot see this) and is
548
+ * retained instead of discarded. The probe is fail-open — see
549
+ * {@link probeAlivePrWorkflowLaneSessions} — so an unavailable, erroring or
550
+ * empty probe leaves the age-only behaviour exactly as it was.
442
551
  */
443
552
  export declare function settlePresumedStalePrWorkflowLanes(directory: string, sessionID: string): Promise<PrWorkflowStaleLaneSettlement>;
444
553
  /**
@@ -480,6 +589,16 @@ export declare function abortPrWorkflow(directory: string, sessionID: string, op
480
589
  openLanes: number;
481
590
  presumedStaleLanes?: string[];
482
591
  presumedStaleDisclosure?: string;
592
+ /** Lanes past the horizon the liveness probe reported as still running. */
593
+ probeRetainedLanes?: string[];
594
+ /**
595
+ * Present ONLY when a human `force` abort cleared the gate while those
596
+ * probe-retained lanes were the sole remaining reason it was blocked
597
+ * (issue #2251 S3).
598
+ */
599
+ probeRetentionOverrideDisclosure?: string;
600
+ /** Why the liveness probe produced no evidence, when it could not run. */
601
+ probeDegradedReason?: PrWorkflowLaneProbeDegradedReason;
483
602
  stateSalvaged?: boolean;
484
603
  stateSalvageDisclosure?: string;
485
604
  casEscapeDisclosure?: string;
@@ -652,6 +771,32 @@ export declare const _test_exports: {
652
771
  removeCheckoutLock: typeof removeCheckoutLockFile;
653
772
  checkoutMutationActionTimeoutMs: number;
654
773
  classifyPrWorkflowGitStateAsync: typeof classifyPrWorkflowGitState;
774
+ /**
775
+ * The durability sweep, reached through a seam so a test can prove that a
776
+ * failing sweep cannot un-settle the decision `settlePresumedStalePrWorkflow-
777
+ * Lanes` already made in memory. It cannot throw today (it catches internally
778
+ * and returns 0) — the seam is what makes that guarantee testable rather than
779
+ * merely asserted.
780
+ */
781
+ sweepStaleDelegationsAsync: typeof sweepStaleDelegations;
782
+ /** The fail-open liveness probe (issue #2251). */
783
+ probeLaneLivenessAsync: typeof probeAlivePrWorkflowLaneSessions;
784
+ /**
785
+ * Session handle for the liveness probe.
786
+ *
787
+ * A seam rather than a direct `swarmState.opencodeClient` read at the call
788
+ * site because 20+ test files mutate that field; without this, this suite and
789
+ * the stale-lane suite would be order-dependent in bun's shared process.
790
+ * Mirrors `_internals.getSessionOps` in `src/tools/dispatch-lanes.ts`.
791
+ */
792
+ getSessionOps: () => PrWorkflowLaneLivenessSessionOps | null;
793
+ /**
794
+ * Probe deadline, read through the seam at CALL time. `freezeClock` patches
795
+ * `Date.now()`, not `setTimeout`, so a test that must reach the timeout branch
796
+ * has to shorten the real deadline. Same precedent as
797
+ * `checkoutMutationActionTimeoutMs` above.
798
+ */
799
+ laneLivenessProbeTimeoutMs: number;
655
800
  resolveCurrentGitHead: typeof resolveCurrentGitHead;
656
801
  resolveCurrentGitHeadAsync: typeof resolveCurrentGitHeadAsync;
657
802
  resolveCurrentUpstreamPushTarget: typeof resolveCurrentUpstreamPushTarget;
@@ -918,6 +1063,17 @@ declare function analyzePrReviewBatchRecordIntegrity(args: {
918
1063
  * accidentally accept stale terminal state or a different output reference.
919
1064
  */
920
1065
  export declare function validatePrReviewDiscoveryLaneCompletion(input: PrReviewDiscoveryLaneValidationInput): PrReviewLaneValidationResult;
1066
+ /**
1067
+ * Collection-time proof for transport-recovered structured workflow lanes.
1068
+ *
1069
+ * Reviewer/critic/PR-feedback lanes normally settle later through the workflow
1070
+ * gate, not in `collect_lane_results`, so a truncated inline preview used to
1071
+ * pass through collection with no durable typed provenance. This helper proves
1072
+ * the durable artifact still carries the exact rows the already-declared batch
1073
+ * owns, allowing collection to persist the transport recovery immediately. Any
1074
+ * unsupported or unprovable structured mode fails closed.
1075
+ */
1076
+ export declare function validatePrWorkflowTransportRecovery(input: PrWorkflowTransportRecoveryValidationInput): Promise<PrWorkflowTransportRecoveryValidationResult>;
921
1077
  /** Require at least one semantically valid discovery row or CLEAN attestation. */
922
1078
  export declare function prReviewDiscoveryArtifactCoversLane(text: string, expectedWorkflowLane: string, ownedWorkflowLanes?: readonly string[], mode?: string): boolean;
923
1079
  /**