opencode-swarm 7.140.3 → 7.140.5

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 (148) hide show
  1. package/.opencode/skills/brainstorm/SKILL.md +1 -1
  2. package/.opencode/skills/ci-failure-batching/SKILL.md +11 -1
  3. package/.opencode/skills/ci-fix-monitor/SKILL.md +6 -4
  4. package/.opencode/skills/discover/SKILL.md +1 -1
  5. package/.opencode/skills/durable-session-state/SKILL.md +82 -0
  6. package/.opencode/skills/engineering-conventions/SKILL.md +1 -1
  7. package/.opencode/skills/issue-ingest/SKILL.md +13 -7
  8. package/.opencode/skills/issue-tracer/SKILL.md +1 -1
  9. package/.opencode/skills/orchestrating-subagents/SKILL.md +113 -0
  10. package/.opencode/skills/parallel-work-check/SKILL.md +1 -1
  11. package/.opencode/skills/plan/SKILL.md +40 -12
  12. package/.opencode/skills/swarm-ci-monitor/SKILL.md +5 -3
  13. package/.opencode/skills/swarm-pr-feedback/SKILL.md +30 -4
  14. package/.opencode/skills/writing-tests/SKILL.md +1 -1
  15. package/dist/agents/architect.d.ts +2 -1
  16. package/dist/agents/reviewer-directive-compliance.d.ts +19 -5
  17. package/dist/background/pending-delegations.d.ts +5 -0
  18. package/dist/cli/{config-doctor-fnmfd35x.js → config-doctor-5vzpq4qa.js} +3 -3
  19. package/dist/cli/{core-p5cyej3r.js → core-xjzdc56e.js} +2 -2
  20. package/dist/cli/{curation-policy-d52h4g8t.js → curation-policy-avvb56x2.js} +6 -8
  21. package/dist/cli/{curator-3zpdqt9r.js → curator-5nytvg7p.js} +38 -38
  22. package/dist/cli/curator-llm-factory-rds75zhj.js +61 -0
  23. package/dist/cli/{evidence-summary-service-nfdc1ht9.js → evidence-summary-service-zq4gyx6g.js} +15 -12
  24. package/dist/cli/gate-evidence-smn2wqft.js +51 -0
  25. package/dist/cli/guardrail-explain-an7jvam1.js +62 -0
  26. package/dist/cli/{guardrail-log-82da8y5a.js → guardrail-log-0hnd2k9v.js} +4 -4
  27. package/dist/cli/{hive-promoter-af5yaxvt.js → hive-promoter-qe8pqg79.js} +38 -38
  28. package/dist/cli/{index-qksjaxpd.js → index-01ggt2mj.js} +49 -18
  29. package/dist/cli/{index-j1xmren9.js → index-0r2m0vbq.js} +12 -10
  30. package/dist/cli/{index-pg7n141e.js → index-0rx9t9w8.js} +1 -1
  31. package/dist/cli/{index-brh827g0.js → index-2bg901qt.js} +73 -32
  32. package/dist/cli/{index-8n4c3vec.js → index-386ts4tm.js} +4 -4
  33. package/dist/cli/{index-898f16j9.js → index-8rp1y4ab.js} +2 -2
  34. package/dist/cli/{index-hfvxhk4z.js → index-912qz4y0.js} +88 -88
  35. package/dist/cli/index-affh1gtg.js +2554 -0
  36. package/dist/cli/{index-1m1ksyqt.js → index-c432knmy.js} +1 -1
  37. package/dist/cli/{index-jvk119ck.js → index-e0mpz2j3.js} +54 -19
  38. package/dist/cli/{index-ry0hgg3m.js → index-epvhf50h.js} +37 -3
  39. package/dist/cli/{index-95bj4kaw.js → index-ex7r16gc.js} +2 -2
  40. package/dist/cli/{index-7d5jseea.js → index-jm4cpp4n.js} +5 -2
  41. package/dist/cli/{index-n408rw7n.js → index-jqsfsqbx.js} +27 -2
  42. package/dist/cli/{index-7kdd75se.js → index-kb5q9v34.js} +11 -9
  43. package/dist/cli/{index-jfjnn408.js → index-m9xrdjn0.js} +1 -1
  44. package/dist/cli/{index-pj9h75cc.js → index-mm2egvdt.js} +40 -40
  45. package/dist/cli/{index-8bnzzv3b.js → index-nwrwy8eb.js} +70 -34
  46. package/dist/cli/index-nyjtzmsj.js +43 -0
  47. package/dist/cli/{index-h2waehqq.js → index-p8kk34am.js} +3 -3
  48. package/dist/cli/{index-wf35ka4z.js → index-ptn13xjn.js} +3 -3
  49. package/dist/cli/{index-1kyex7z2.js → index-qwm6vdyv.js} +32 -1
  50. package/dist/cli/{index-p9dsb0tw.js → index-qy1nq52t.js} +2 -19
  51. package/dist/cli/{index-b9rd29ge.js → index-s1v0wza5.js} +6 -2
  52. package/dist/cli/{index-yyyk63kk.js → index-t5pytnca.js} +2 -2
  53. package/dist/cli/index-tjqzr3jc.js +623 -0
  54. package/dist/cli/{index-rs1f1bh0.js → index-vh05t3w5.js} +1 -1
  55. package/dist/cli/{index-adyxbmt5.js → index-wkt9fj06.js} +4 -4
  56. package/dist/cli/{index-kbfsp07d.js → index-wrb0gykj.js} +217 -15
  57. package/dist/cli/{index-xz8f1n1a.js → index-z7h37d63.js} +2 -2
  58. package/dist/cli/{index-q1q8b85k.js → index-z90nvqj3.js} +49315 -47331
  59. package/dist/cli/{index-b8zgtz81.js → index-zsrtt42s.js} +34 -1
  60. package/dist/cli/{index-gtbmabws.js → index-ztgn70jz.js} +2 -2
  61. package/dist/cli/index.js +37 -37
  62. package/dist/cli/{knowledge-escalator-7q59skqg.js → knowledge-escalator-4pfrc902.js} +20 -8
  63. package/dist/cli/{knowledge-events-3nwfdpq7.js → knowledge-events-3zkfnksk.js} +19 -6
  64. package/dist/cli/{knowledge-link-q46k9adx.js → knowledge-link-m9p80f4r.js} +5 -5
  65. package/dist/cli/{knowledge-store-0d83rhh3.js → knowledge-store-dpqgvvjt.js} +6 -6
  66. package/dist/cli/{knowledge-validator-6mfx91a2.js → knowledge-validator-2c7w87dk.js} +8 -9
  67. package/dist/cli/{pending-delegations-qzrx38y9.js → pending-delegations-cxx9tezp.js} +4 -4
  68. package/dist/cli/{pr-subscriptions-5s59h4dd.js → pr-subscriptions-2sfnb599.js} +4 -4
  69. package/dist/cli/{runner-y78d7ryb.js → runner-mky3vvht.js} +6 -6
  70. package/dist/cli/{scan-cursor-rc8q12ss.js → scan-cursor-1z60gwrw.js} +7 -7
  71. package/dist/cli/{schema-n9eaxp3a.js → schema-vpnkwvez.js} +2 -2
  72. package/dist/cli/{scope-persistence-dr1msqxw.js → scope-persistence-p9dmprry.js} +10 -5
  73. package/dist/cli/{skill-generator-q7c6vadg.js → skill-generator-yx7ka1cj.js} +19 -10
  74. package/dist/cli/{telemetry-sc57xtb0.js → telemetry-0x6kszvk.js} +1 -1
  75. package/dist/cli/{worktree-collision-ownership-7a8e6gr9.js → worktree-collision-ownership-wm5pse49.js} +8 -8
  76. package/dist/cli/worktree-isolation-bwc6ra8e.js +102 -0
  77. package/dist/cli/worktree-provisioning-owner-sjh7te1h.js +22 -0
  78. package/dist/commands/acknowledge-spec-drift.d.ts +4 -5
  79. package/dist/commands/ci-simulate.d.ts +7 -3
  80. package/dist/commands/close.d.ts +8 -0
  81. package/dist/commands/registry.d.ts +2 -2
  82. package/dist/commands/sdd.d.ts +15 -0
  83. package/dist/config/bundled-skills.d.ts +1 -1
  84. package/dist/config/evidence-schema.d.ts +3 -3
  85. package/dist/config/index.d.ts +2 -2
  86. package/dist/config/plan-schema.d.ts +8 -0
  87. package/dist/config/schema.d.ts +4 -2
  88. package/dist/council/council-evidence-writer.d.ts +1 -1
  89. package/dist/gate-evidence.d.ts +117 -4
  90. package/dist/git/branch.d.ts +1 -1
  91. package/dist/hooks/delegate-ack-collector.d.ts +5 -0
  92. package/dist/hooks/delegation-gate.d.ts +21 -0
  93. package/dist/hooks/hive-promoter.d.ts +4 -4
  94. package/dist/hooks/issue-trace-reducer.d.ts +7 -1
  95. package/dist/hooks/issue-trace-state.d.ts +18 -0
  96. package/dist/hooks/issue-trace.d.ts +3 -1
  97. package/dist/hooks/knowledge-application-gate.d.ts +8 -3
  98. package/dist/hooks/knowledge-application.d.ts +8 -5
  99. package/dist/hooks/knowledge-escalator.d.ts +9 -5
  100. package/dist/hooks/knowledge-events.d.ts +21 -8
  101. package/dist/hooks/knowledge-injector.d.ts +9 -0
  102. package/dist/hooks/knowledge-receipt-ledger-storage.d.ts +49 -0
  103. package/dist/hooks/knowledge-receipt-ledger.d.ts +305 -0
  104. package/dist/hooks/knowledge-receipt-observability.d.ts +28 -0
  105. package/dist/hooks/knowledge-receipt-validator.d.ts +13 -50
  106. package/dist/hooks/knowledge-store.d.ts +6 -1
  107. package/dist/hooks/knowledge-types.d.ts +12 -0
  108. package/dist/hooks/phase-complete-directive-gate.d.ts +3 -1
  109. package/dist/hooks/phase-directives.d.ts +4 -4
  110. package/dist/hooks/pr-workflow-gate.d.ts +34 -1
  111. package/dist/hooks/promotion-evidence-store.d.ts +14 -8
  112. package/dist/hooks/reviewer-verdict-parser.d.ts +34 -10
  113. package/dist/index.js +823 -779
  114. package/dist/knowledge/curation-policy.d.ts +0 -2
  115. package/dist/observability/catalog.d.ts +5 -3
  116. package/dist/observability/legacy.d.ts +4 -3
  117. package/dist/plan/ledger.d.ts +55 -0
  118. package/dist/plan/manager.d.ts +9 -0
  119. package/dist/plan/planning-profile.d.ts +27 -0
  120. package/dist/services/spec-drift-recovery.d.ts +84 -0
  121. package/dist/session/snapshot-writer.d.ts +3 -1
  122. package/dist/state.d.ts +19 -17
  123. package/dist/summaries/schema.d.ts +2 -2
  124. package/dist/telemetry.d.ts +1 -1
  125. package/dist/tools/convene-council.d.ts +6 -6
  126. package/dist/tools/index.d.ts +3 -0
  127. package/dist/tools/manifest.d.ts +3 -0
  128. package/dist/tools/phase-complete.d.ts +9 -0
  129. package/dist/tools/rebind-pr-feedback-head.d.ts +17 -0
  130. package/dist/tools/record-implementation-review.d.ts +19 -0
  131. package/dist/tools/record-recurrence-sweep.d.ts +17 -0
  132. package/dist/tools/run-pr-feedback-stage-a.d.ts +8 -0
  133. package/dist/tools/save-plan.d.ts +8 -0
  134. package/dist/tools/submit-phase-council-verdicts.d.ts +6 -6
  135. package/dist/tools/tool-metadata.d.ts +40 -28
  136. package/dist/tools/update-task-status.d.ts +13 -0
  137. package/dist/tools/write-final-council-evidence.d.ts +6 -6
  138. package/dist/types/events.d.ts +29 -1
  139. package/dist/workflow/coder-settlement.d.ts +62 -0
  140. package/dist/workflow/task-repair.d.ts +30 -0
  141. package/dist/workflow/task-terminal.d.ts +52 -0
  142. package/package.json +3 -1
  143. package/dist/cli/curator-llm-factory-2h0xb62t.js +0 -61
  144. package/dist/cli/gate-evidence-46qeyfc1.js +0 -32
  145. package/dist/cli/guardrail-explain-yktan15c.js +0 -62
  146. package/dist/cli/index-d181x9zr.js +0 -71
  147. package/dist/cli/index-n0pja0qs.js +0 -239
  148. package/dist/cli/index-n8jncheh.js +0 -666
@@ -26,7 +26,6 @@
26
26
  * the destructive callers (Layer 4 routing).
27
27
  */
28
28
  import { readFile } from 'node:fs/promises';
29
- import { readKnowledgeEvents } from '../hooks/knowledge-events.js';
30
29
  import { isLinked, readLinkPointer, resolveKnowledgeStoreDir, resolveLinkDir } from '../hooks/knowledge-link.js';
31
30
  import type { CurationAction, CurationEvidenceScope, CurationProposal, KnowledgeConfig } from '../hooks/knowledge-types.js';
32
31
  import { type CohortConfigFingerprintInput, cohortConfigFingerprint } from './config-fingerprint.js';
@@ -114,7 +113,6 @@ export declare function readCohortConfigFingerprint(directory: string): Promise<
114
113
  */
115
114
  export declare const _internals: {
116
115
  resolveWorktreeId: typeof resolveWorktreeId;
117
- readKnowledgeEvents: typeof readKnowledgeEvents;
118
116
  cohortConfigFingerprint: typeof cohortConfigFingerprint;
119
117
  readCohortConfigFingerprint: typeof readCohortConfigFingerprint;
120
118
  readFile: typeof readFile;
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * The event catalog (issue #2029).
3
3
  *
4
- * Exactly 40 entries, matching the `TelemetryEvent` union at
4
+ * Exactly 41 entries, matching the `TelemetryEvent` union at
5
5
  * `src/telemetry.ts:15-91`. Thirty-eight predate the #2029 contract; the 39th is
6
6
  * `agent_conflict_detected` (previously emitted through a force-cast past the
7
7
  * type system), and the 40th is `close_archive_result` (issue #2030 — the
8
- * structured close/archive result event). Both late additions are instances of
8
+ * structured close/archive result event). The 41st is the bounded diagnostic
9
+ * projection of authoritative knowledge-receipt transitions (issue #2031).
10
+ * These late additions are instances of
9
11
  * the defect class this contract exists to close: an event kind entering the
10
12
  * stream with no registration.
11
13
  *
@@ -60,7 +62,7 @@ export interface CatalogEntry {
60
62
  /**
61
63
  * Whether an event of this kind must carry `trace.parentSpanId`.
62
64
  *
63
- * `false` for all 40 entries today, and that is a truthful statement about
65
+ * `false` for all 41 entries today, and that is a truthful statement about
64
66
  * the current system rather than a placeholder: no producer supplies a
65
67
  * parent span, so `createObservation` never sets one. Setting this to `true`
66
68
  * for a kind whose producer cannot supply a parent would make every
@@ -53,9 +53,10 @@ export declare function adaptLegacyTelemetryPayload(kind: string, data: unknown,
53
53
  * Shallow, never throws, and NEVER synthesizes: an ID that is absent, empty, or
54
54
  * of the wrong type stays `undefined`. Only the mappings a producer actually
55
55
  * populates are implemented — `sessionId` to `hostSessionId`, `taskId`, `phase`
56
- * to `phaseId`, `laneId`, `batchId`. The remaining eight recognized IDs have no
57
- * current producer, and inventing an extraction for them would manufacture
58
- * exactly the joins issue #2029 item 2 forbids.
56
+ * to `phaseId`, `laneId`, `batchId`, plus the canonical receipt payload keys
57
+ * `knowledgeTraceId` and `knowledgeEntryId`. Unmapped IDs stay absent; inventing
58
+ * an extraction for them would manufacture exactly the joins issue #2029 item 2
59
+ * forbids.
59
60
  */
60
61
  export declare function extractWorkflowIds(data: unknown): WorkflowIds;
61
62
  /**
@@ -78,6 +78,28 @@ declare function getLedgerPath(directory: string): string;
78
78
  * Get the path to plan.json
79
79
  */
80
80
  declare function getPlanJsonPath(directory: string): string;
81
+ /**
82
+ * Durable atomic write: write `data` to `tempPath`, fsync the file descriptor so
83
+ * the bytes are flushed to stable storage, then atomically rename it over
84
+ * `targetPath`.
85
+ *
86
+ * WHY the fsync matters: a plain `writeFileSync` returns once the data is in the
87
+ * OS page cache, not on disk. A crash/power-loss between the write and the
88
+ * subsequent `rename` can publish a zero-length or partially-written temp file as
89
+ * the canonical ledger — silent truncation that later reads cannot distinguish
90
+ * from a legitimately short ledger. Forcing an fsync before the rename guarantees
91
+ * the temp file's bytes are durable before it becomes the canonical file.
92
+ *
93
+ * NOTE: the containing-directory fsync (which would also durably persist the
94
+ * rename's directory entry so the *rename itself* survives a crash) is
95
+ * intentionally OMITTED. The rename is atomic on POSIX, and the ledger's
96
+ * crash-consistency contract only requires that a published ledger never be
97
+ * partially-written; it tolerates losing the very last rename on power-loss (the
98
+ * prior canonical file is then still intact). Omitting the dir-fsync avoids the
99
+ * portability and cost concerns of opening the directory as a file descriptor.
100
+ */
101
+ declare function writeFileFsyncedThenRename(tempPath: string, targetPath: string, data: string | Uint8Array): void;
102
+ declare function fsyncRecoveryDirectory(directory: string): void;
81
103
  /**
82
104
  * Compute a SHA-256 hash of the plan state.
83
105
  * Uses deterministic JSON serialization for consistent hashing.
@@ -163,6 +185,13 @@ export declare function initLedger(directory: string, planId: string, initialPla
163
185
  export declare function appendLedgerEvent(directory: string, eventInput: LedgerEventInput, options?: {
164
186
  expectedSeq?: number;
165
187
  expectedHash?: string;
188
+ /**
189
+ * CAS against the durable ledger tail rather than plan.json. This is used
190
+ * only by stale-projection reconciliation, where plan.json intentionally
191
+ * differs from the ledger and a snapshot adopts that exact projection as
192
+ * the new authoritative state.
193
+ */
194
+ expectedLedgerHash?: string;
166
195
  planHashAfter?: string;
167
196
  }): Promise<LedgerEvent>;
168
197
  /**
@@ -244,7 +273,31 @@ export declare function takeSnapshotEvent(directory: string, plan: Plan, options
244
273
  source?: string;
245
274
  approvalMetadata?: Record<string, unknown>;
246
275
  payloadHashOverride?: string;
276
+ /** CAS binding for stale-projection recovery snapshots. */
277
+ expectedSeq?: number;
278
+ /** Previous durable hash used to preserve the ledger hash chain. */
279
+ expectedLedgerHash?: string;
247
280
  }): Promise<LedgerEvent>;
281
+ export interface TruncatedLedgerRecoveryResult {
282
+ archivePath: string;
283
+ archiveSha256: string;
284
+ recoveryRoot: LedgerEvent;
285
+ }
286
+ /**
287
+ * Recover an explicitly verified stale projection from a malformed ledger.
288
+ *
289
+ * A snapshot appended after an unparsable line is not durable recovery because
290
+ * integrity replay stops at that line after restart. This transaction first
291
+ * writes and fsyncs a byte-for-byte archive of the complete canonical ledger,
292
+ * then atomically replaces the canonical file with a new `plan_created` root
293
+ * that embeds the verified projection and links to the preserved archive.
294
+ * A crash therefore leaves either the old canonical ledger or the new complete
295
+ * root; it never creates a missing-ledger window or silently discards history.
296
+ */
297
+ export declare function replaceTruncatedLedgerWithRecoveryRoot(directory: string, plan: Plan, expected: {
298
+ seq: number;
299
+ ledgerHash: string;
300
+ }): Promise<TruncatedLedgerRecoveryResult>;
248
301
  /**
249
302
  * Options for replayFromLedger
250
303
  */
@@ -461,5 +514,7 @@ export declare const _internals: {
461
514
  loadLastPlanCriticApprovedSnapshot: typeof loadLastPlanCriticApprovedSnapshot;
462
515
  getLedgerPath: typeof getLedgerPath;
463
516
  getPlanJsonPath: typeof getPlanJsonPath;
517
+ writeFileFsyncedThenRename: typeof writeFileFsyncedThenRename;
518
+ fsyncRecoveryDirectory: typeof fsyncRecoveryDirectory;
464
519
  };
465
520
  export {};
@@ -146,6 +146,15 @@ export declare function savePlan(directory: string, plan: Plan, options?: {
146
146
  acknowledged_removals?: AcknowledgedRemovals;
147
147
  /** True only when the caller already owns the canonical plan.json lock. */
148
148
  planLockAlreadyHeld?: boolean;
149
+ /**
150
+ * Narrow recovery mode for a semantically unreadable ledger tail. The
151
+ * caller must bind the exact tail observed while validating an unchanged
152
+ * `_ledgerReplayStale` projection.
153
+ */
154
+ staleProjectionReconcile?: {
155
+ expectedSeq: number;
156
+ expectedLedgerHash: string;
157
+ };
149
158
  }): Promise<void>;
150
159
  /**
151
160
  * Rebuild plan from ledger events.
@@ -0,0 +1,27 @@
1
+ import type { ExecutionProfile, Plan } from '../config/plan-schema';
2
+ import type { PluginConfig } from '../config/schema';
3
+ export type PlanningProfile = NonNullable<NonNullable<ExecutionProfile['planning_profile']>>;
4
+ export interface ResolvedPlanningProfile {
5
+ effective: PlanningProfile;
6
+ persisted: PlanningProfile | undefined;
7
+ source: 'incoming' | 'persisted' | 'repository_default' | 'legacy_locked_default';
8
+ }
9
+ export type PlanningProfileDirectiveContext = 'repository_default' | 'runtime';
10
+ /**
11
+ * Render the authoritative planning ceremony for the architect prompt.
12
+ *
13
+ * Keep this policy next to the resolver so static agent construction and
14
+ * per-turn persisted-plan injection cannot drift into different meanings for
15
+ * the same resolved profile.
16
+ */
17
+ export declare function renderPlanningProfileDirective(resolution: ResolvedPlanningProfile, context?: PlanningProfileDirectiveContext): string;
18
+ interface ResolvePlanningProfileOptions {
19
+ directory: string;
20
+ incomingExecutionProfile?: Partial<ExecutionProfile>;
21
+ existingExecutionProfile?: Plan['execution_profile'];
22
+ resetStatuses?: boolean;
23
+ config?: Pick<PluginConfig, 'execution_mode'>;
24
+ }
25
+ export declare function resolvePlanningProfile({ directory, incomingExecutionProfile, existingExecutionProfile, resetStatuses, config, }: ResolvePlanningProfileOptions): ResolvedPlanningProfile;
26
+ export declare function normalizeExecutionProfileForHash(profile: Plan['execution_profile']): Record<string, unknown> | undefined;
27
+ export {};
@@ -0,0 +1,84 @@
1
+ import { validateSwarmPath } from '../hooks/utils.js';
2
+ import { tryAcquireLock } from '../parallel/file-locks.js';
3
+ import { takeSnapshotEvent } from '../plan/ledger.js';
4
+ import { loadPlanJsonOnly, savePlan } from '../plan/manager.js';
5
+ import { readEffectiveSpecSync } from '../sdd/effective-spec.js';
6
+ import type { SpecDriftAcknowledgedEvent, SpecDriftRepairedEvent } from '../types/events.js';
7
+ import { bunWrite } from '../utils/bun-compat.js';
8
+ import { assertProjectRoot } from '../utils/project-boundary.js';
9
+ import { invalidateCachedArtifact } from '../utils/swarm-artifact-cache.js';
10
+ type RecoveryMode = 'acknowledge' | 'repair';
11
+ type RecoveryActor = 'cli' | 'spec_write' | 'unknown' | 'user';
12
+ type RecoveryState = 'COMMITTED' | 'PREPARED';
13
+ interface SpecStalenessMarker {
14
+ planTitle: string;
15
+ phase: number;
16
+ specHash_plan: string | null;
17
+ specHash_current: string | null;
18
+ reason: string;
19
+ timestamp: string;
20
+ }
21
+ interface SpecDriftRecoveryWal {
22
+ version: 2;
23
+ mode: RecoveryMode;
24
+ state: RecoveryState;
25
+ transitionId: string;
26
+ markerHash: string;
27
+ planTitle: string;
28
+ phase: number;
29
+ previousHash: string | null;
30
+ newHash: string | null;
31
+ specContent: string | null;
32
+ actor: RecoveryActor;
33
+ recordedAt: string;
34
+ }
35
+ export interface SpecDriftRecoveryResult {
36
+ status: 'applied' | 'cleanup_pending' | 'corrupt_marker' | 'failed' | 'no_marker' | 'retry_later';
37
+ mode: RecoveryMode;
38
+ message: string;
39
+ phase?: number;
40
+ planTitle?: string;
41
+ previousHash?: string | null;
42
+ newHash?: string | null;
43
+ transitionId?: string;
44
+ }
45
+ export declare const _internals: {
46
+ appendEvent: typeof appendEvent;
47
+ assertProjectRoot: typeof assertProjectRoot;
48
+ bunWrite: typeof bunWrite;
49
+ invalidateCachedArtifact: typeof invalidateCachedArtifact;
50
+ loadPlanJsonOnly: typeof loadPlanJsonOnly;
51
+ now: typeof now;
52
+ parseMarker: typeof parseMarker;
53
+ parseWal: typeof parseWal;
54
+ readEffectiveSpecSync: typeof readEffectiveSpecSync;
55
+ readFileText: typeof readFileText;
56
+ savePlan: typeof savePlan;
57
+ tryAcquireLock: typeof tryAcquireLock;
58
+ takeSnapshotEvent: typeof takeSnapshotEvent;
59
+ unlinkIfExists: typeof unlinkIfExists;
60
+ validateSwarmPath: typeof validateSwarmPath;
61
+ verifyEventPresence: typeof verifyEventPresence;
62
+ ensureSnapshotEvent: typeof ensureSnapshotEvent;
63
+ verifySnapshot: typeof verifySnapshot;
64
+ writeWal: typeof writeWal;
65
+ };
66
+ declare function now(): string;
67
+ declare function parseMarker(raw: string): SpecStalenessMarker | null;
68
+ declare function parseWal(raw: string): SpecDriftRecoveryWal | null;
69
+ declare function readFileText(filePath: string): Promise<string | null>;
70
+ declare function unlinkIfExists(filePath: string): Promise<boolean>;
71
+ declare function writeWal(walPath: string, wal: SpecDriftRecoveryWal): Promise<void>;
72
+ declare function verifySnapshot(snapshotPath: string, currentSpec: {
73
+ content: string;
74
+ } | null): Promise<void>;
75
+ declare function ensureSnapshotEvent(directory: string, plan: NonNullable<Awaited<ReturnType<typeof loadPlanJsonOnly>>>, transitionId: string): Promise<void>;
76
+ declare function appendEvent(eventsPath: string, event: SpecDriftAcknowledgedEvent | SpecDriftRepairedEvent): Promise<void>;
77
+ declare function verifyEventPresence(eventsPath: string, eventType: 'spec_drift_acknowledged' | 'spec_drift_repaired', transitionId: string): Promise<boolean>;
78
+ export declare function reconcileSpecDrift(directory: string, options: {
79
+ mode: RecoveryMode;
80
+ actor: RecoveryActor;
81
+ /** Caller already holds the spec.md lock across the canonical spec write. */
82
+ specLockAlreadyHeld?: boolean;
83
+ }): Promise<SpecDriftRecoveryResult>;
84
+ export {};
@@ -2,6 +2,7 @@
2
2
  * Session snapshot writer for OpenCode Swarm plugin.
3
3
  * Serializes swarmState to .swarm/session/state.json using atomic write (temp-file + rename).
4
4
  */
5
+ import { TASK_WORKFLOW_SCHEMA_MARKER } from '../gate-evidence.js';
5
6
  import type { AgentSessionState, DelegationEntry, ToolAggregate } from '../state';
6
7
  import { swarmState } from '../state';
7
8
  /**
@@ -114,8 +115,9 @@ export interface SerializedInvocationWindow {
114
115
  * Snapshot data structure written to disk
115
116
  */
116
117
  export interface SnapshotData {
117
- version: 1 | 2;
118
+ version: 1 | 2 | 3;
118
119
  writtenAt: number;
120
+ workflowSchema?: typeof TASK_WORKFLOW_SCHEMA_MARKER;
119
121
  toolAggregates: Record<string, ToolAggregate>;
120
122
  activeAgent: Record<string, string>;
121
123
  delegationChains: Record<string, DelegationEntry[]>;
package/dist/state.d.ts CHANGED
@@ -10,6 +10,7 @@ import type { OpencodeClient } from '@opencode-ai/sdk';
10
10
  import type { CouncilAgent } from './council/types';
11
11
  import { type QaGates } from './db/qa-gate-profile.js';
12
12
  import { type EnvironmentProfile } from './environment/profile.js';
13
+ import { type TaskWorkflowMetadata } from './gate-evidence';
13
14
  import type { EscalationTracker } from './prm/escalation.js';
14
15
  import type { PatternMatch } from './prm/types.js';
15
16
  import { AgentRunContext } from './state/agent-run-context.js';
@@ -63,7 +64,14 @@ export interface PrSubscriptionState {
63
64
  * Per-task workflow state for gate progression tracking.
64
65
  * Transitions must be forward-only: idle → coder_delegated → pre_check_passed → reviewer_run → tests_run → complete
65
66
  */
66
- export type TaskWorkflowState = 'idle' | 'coder_delegated' | 'pre_check_passed' | 'reviewer_run' | 'tests_run' | 'complete';
67
+ export type TaskWorkflowState = 'idle' | 'coder_delegated' | 'pre_check_passed' | 'reviewer_run' | 'tests_run' | 'rework_required' | 'complete' | 'blocked';
68
+ export interface TaskWorkflowCacheEntry {
69
+ generation: number;
70
+ retryCount: number;
71
+ lastOutcome: TaskWorkflowMetadata['lastOutcome'];
72
+ lastTransitionId: string | null;
73
+ updatedAt: string;
74
+ }
67
75
  /**
68
76
  * Upper bound for per-session task file-attribution entries.
69
77
  *
@@ -187,6 +195,8 @@ export interface AgentSessionState {
187
195
  qaSkipTaskIds: string[];
188
196
  /** Per-task workflow state — taskId → current state */
189
197
  taskWorkflowStates: Map<string, TaskWorkflowState>;
198
+ /** Exact-task workflow cache keyed by taskId. Durable evidence remains authoritative. */
199
+ taskWorkflowCache?: Map<string, TaskWorkflowCacheEntry>;
190
200
  /**
191
201
  * PR 2 Stage B barrier: per-task set of completed Stage B agents.
192
202
  * Order-independent — either 'reviewer' or 'test_engineer' may complete first.
@@ -213,6 +223,8 @@ export interface AgentSessionState {
213
223
  */
214
224
  rewarded?: boolean;
215
225
  }>;
226
+ /** Generation captured when the first member of a task council is dispatched. */
227
+ taskCouncilWorkflowGeneration?: Map<string, number>;
216
228
  /**
217
229
  * Per-(task,round) required council members for the next submission attempt.
218
230
  * Key format: `${taskId}:${roundNumber}`.
@@ -1026,6 +1038,7 @@ export declare function resetModifiedFilesForTask(session: AgentSessionState, ta
1026
1038
  * Epic sessions retain it until `epic_record_divergence` consumes the entry.
1027
1039
  */
1028
1040
  export declare function completeModifiedFilesForTask(session: AgentSessionState, taskId: string): void;
1041
+ export declare function updateTaskWorkflowCache(session: AgentSessionState, taskId: string, overrides: Partial<TaskWorkflowCacheEntry>): void;
1029
1042
  /**
1030
1043
  * Advance a task's workflow state. Validates forward-only transitions.
1031
1044
  * Throws 'INVALID_TASK_STATE_TRANSITION: [taskId] [current] → [requested]' on illegal transition.
@@ -1061,23 +1074,12 @@ export declare function canAdvanceTaskState(session: AgentSessionState, taskId:
1061
1074
  requireAllMembers?: boolean;
1062
1075
  }): boolean;
1063
1076
  /**
1064
- * Advance the per-task workflow state machine AND persist the corresponding
1065
- * plan.json status at meaningful workflow boundaries.
1066
- *
1067
- * The two-layer model splits in-memory workflow state (Layer 1, fast, used by
1068
- * gates) from the durable plan (Layer 2, projected to plan.md). Without this
1069
- * bridge, council APPROVE → 'complete' updates Layer 1 only and plan.md goes
1070
- * stale. This helper closes the gap by mapping:
1071
- * - 'coder_delegated' → plan.json status 'in_progress'
1072
- * - 'complete' → plan.json status 'completed'
1073
- * Other transitions are in-memory only (the task is already in_progress on disk
1074
- * once coder_delegated has fired).
1075
- *
1076
- * Persistence errors are logged and swallowed so a transient disk failure does
1077
- * not break the in-memory state machine — matches the existing defensive
1078
- * pattern around advanceTaskState call sites.
1077
+ * Legacy compatibility wrapper for diagnostic-only intermediate projections.
1078
+ * Durable coder/terminal boundaries must use the exact-task evidence reducer
1079
+ * and the plan→evidence transaction/WAL; this wrapper intentionally refuses
1080
+ * those states so no caller can recreate the former split-brain writer.
1079
1081
  */
1080
- export declare function advanceTaskStateAndPersist(session: AgentSessionState, taskId: string, newState: TaskWorkflowState, directory: string, options?: {
1082
+ export declare function advanceTaskStateAndPersist(session: AgentSessionState, taskId: string, newState: TaskWorkflowState, _directory: string, options?: {
1081
1083
  telemetrySessionId?: string;
1082
1084
  emitTelemetry?: boolean;
1083
1085
  }, councilConfig?: {
@@ -22,8 +22,8 @@ export declare const MAX_LIST_ITEMS = 5;
22
22
  /** Verdict vocabulary — mirrors the phase-council gate (APPROVE | CONCERNS | REJECT). */
23
23
  export declare const SupervisorVerdictSchema: z.ZodEnum<{
24
24
  APPROVE: "APPROVE";
25
- REJECT: "REJECT";
26
25
  CONCERNS: "CONCERNS";
26
+ REJECT: "REJECT";
27
27
  }>;
28
28
  export type SupervisorVerdict = z.infer<typeof SupervisorVerdictSchema>;
29
29
  /** Count whitespace-delimited words in a string. */
@@ -130,8 +130,8 @@ export declare const ArchitectureSupervisorReportSchema: z.ZodObject<{
130
130
  phase: z.ZodNumber;
131
131
  verdict: z.ZodEnum<{
132
132
  APPROVE: "APPROVE";
133
- REJECT: "REJECT";
134
133
  CONCERNS: "CONCERNS";
134
+ REJECT: "REJECT";
135
135
  }>;
136
136
  findings: z.ZodDefault<z.ZodArray<z.ZodObject<{
137
137
  severity: z.ZodEnum<{
@@ -26,7 +26,7 @@ export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activa
26
26
  * `prm_hard_stop` TRIGGER emitted by `src/prm/escalation.ts`. A trigger with
27
27
  * no matching delivery means the containment never reached the agent.
28
28
  */
29
- | 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result';
29
+ | 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result' | 'knowledge_receipt_transition';
30
30
  /** Stable classification for how a reviewer-gate decision was established. */
31
31
  export type ReviewerGateEvidenceKind = 'genuine' | 'fallback' | 'data_quality' | 'block';
32
32
  /**
@@ -8,23 +8,23 @@ export declare const ArgsSchema: z.ZodObject<{
8
8
  verdicts: z.ZodArray<z.ZodObject<{
9
9
  agent: z.ZodEnum<{
10
10
  reviewer: "reviewer";
11
- test_engineer: "test_engineer";
11
+ critic: "critic";
12
12
  explorer: "explorer";
13
+ test_engineer: "test_engineer";
13
14
  sme: "sme";
14
- critic: "critic";
15
15
  }>;
16
16
  verdict: z.ZodEnum<{
17
17
  APPROVE: "APPROVE";
18
- REJECT: "REJECT";
19
18
  CONCERNS: "CONCERNS";
19
+ REJECT: "REJECT";
20
20
  }>;
21
21
  confidence: z.ZodNumber;
22
22
  findings: z.ZodArray<z.ZodObject<{
23
23
  severity: z.ZodEnum<{
24
- LOW: "LOW";
25
- MEDIUM: "MEDIUM";
26
- HIGH: "HIGH";
27
24
  CRITICAL: "CRITICAL";
25
+ HIGH: "HIGH";
26
+ MEDIUM: "MEDIUM";
27
+ LOW: "LOW";
28
28
  }>;
29
29
  category: z.ZodString;
30
30
  location: z.ZodString;
@@ -106,8 +106,11 @@ export { lean_turbo_status } from './lean-turbo-status';
106
106
  export { lint_spec } from './lint-spec';
107
107
  export { mutation_test } from './mutation-test';
108
108
  export { executePreparePrWorkflowCheckout, prepare_pr_workflow_checkout, } from './prepare-pr-workflow-checkout';
109
+ export { executeRebindPrFeedbackHead, rebind_pr_feedback_head, } from './rebind-pr-feedback-head';
110
+ export { executeRecordImplementationReview, record_implementation_review, } from './record-implementation-review';
109
111
  export { executeRecordIssuePublication, record_issue_publication, } from './record-issue-publication';
110
112
  export { executeRecordIssueReproduction, record_issue_reproduction, } from './record-issue-reproduction';
113
+ export { executeRecordRecurrenceSweep, record_recurrence_sweep, } from './record-recurrence-sweep';
111
114
  export { executeRunPrFeedbackStageA, run_pr_feedback_stage_a, } from './run-pr-feedback-stage-a';
112
115
  export { symbols } from './symbols';
113
116
  export { type SyntaxCheckFileResult, type SyntaxCheckInput, type SyntaxCheckResult, syntax_check, syntaxCheck, } from './syntax-check';
@@ -46,8 +46,11 @@ export declare const TOOL_MANIFEST: {
46
46
  abort_pr_workflow: () => ToolDefinition;
47
47
  approve_plan_critic: () => ToolDefinition;
48
48
  prepare_pr_workflow_checkout: () => ToolDefinition;
49
+ record_implementation_review: () => ToolDefinition;
49
50
  record_issue_publication: () => ToolDefinition;
50
51
  record_issue_reproduction: () => ToolDefinition;
52
+ record_recurrence_sweep: () => ToolDefinition;
53
+ rebind_pr_feedback_head: () => ToolDefinition;
51
54
  run_pr_feedback_stage_a: () => ToolDefinition;
52
55
  submit_council_verdicts: () => ToolDefinition;
53
56
  submit_phase_council_verdicts: () => ToolDefinition;
@@ -3,6 +3,15 @@
3
3
  * Core implementation - gathers data, enforces policy, writes event, resets state.
4
4
  */
5
5
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
6
+ /** Narrow seam for receipt/plan ordering tests. */
7
+ export declare const phaseCompleteReceiptInternals: {
8
+ recordPhaseCloseIntent: (directory: string, phase: string, sessionId?: string, taskId?: string) => Promise<import("../hooks/knowledge-receipt-ledger.js").ReceiptLedgerResult<{
9
+ event_id: string;
10
+ }>>;
11
+ commitPhaseClosed: (directory: string, phase: string, sessionId?: string, taskId?: string) => Promise<import("../hooks/knowledge-receipt-ledger.js").ReceiptLedgerResult<{
12
+ event_id: string;
13
+ }>>;
14
+ };
6
15
  import type { ReviewModelDispatcher } from '../review/contracts.js';
7
16
  import type { ReviewAgentModelRegistry } from '../review/runtime.js';
8
17
  /**
@@ -0,0 +1,17 @@
1
+ /**
2
+ * rebind_pr_feedback_head — controlled base-sync/rebind transition for a
3
+ * PR_FEEDBACK workflow (issue #2131 criterion C2).
4
+ *
5
+ * After a merge/rebase used to resolve base drift or conflicts, the local
6
+ * history is no longer a direct child of the immutable intake head, so the
7
+ * ordinary exactly-one-reviewed-commit publication path can never be satisfied.
8
+ * This tool moves the intake head to the new verified remote PR head and
9
+ * invalidates every ancestry-bound receipt (Stage A, verification batches,
10
+ * ordered gates), forcing the full mechanical ladder to re-run on the new
11
+ * ancestry. Refuses while publication is armed or while lanes are in flight.
12
+ */
13
+ import { createSwarmTool } from './create-tool';
14
+ export declare function executeRebindPrFeedbackHead(args: unknown, directory: string, context?: {
15
+ sessionID?: string;
16
+ }): Promise<string>;
17
+ export declare const rebind_pr_feedback_head: ReturnType<typeof createSwarmTool>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * record_implementation_review — persist an issue-bound independent
3
+ * implementation-review receipt for the issue-trace workflow (issue #2131
4
+ * residual criterion B).
5
+ *
6
+ * Records that FRESH-context reviewer and critic passes (separate contexts
7
+ * from the implementer) both delivered APPROVE verdicts over the
8
+ * implementation diff. This is an agent self-attestation of the review
9
+ * discipline — it records the verdicts, the reviewed diff range, and the
10
+ * calling session, but does not itself authenticate that the review contexts
11
+ * were genuinely fresh; under PR-review/feedback modes the mechanically
12
+ * authenticated reviewer gates remain the PR-workflow machinery. The trace
13
+ * engine will not hand off to commit-pr until this receipt exists.
14
+ */
15
+ import { createSwarmTool } from './create-tool';
16
+ export declare function executeRecordImplementationReview(args: unknown, directory: string, context?: {
17
+ sessionID?: string;
18
+ }): Promise<string>;
19
+ export declare const record_implementation_review: ReturnType<typeof createSwarmTool>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * record_recurrence_sweep — persist an issue-bound recurrence-sweep receipt for
3
+ * the issue-trace workflow (issue #2131 residual criterion B).
4
+ *
5
+ * Modeled on issue-tracer Phase 4.2: for a real defect class the sweep must
6
+ * record the pattern statement, explicit search predicates, a typed
7
+ * disposition for every hit, and a guardrail with proof it catches the
8
+ * original defect. The "no defect class" fast path (a change that corrects no
9
+ * incorrect behavior) requires a one-line justification. The trace engine will
10
+ * not hand off to commit-pr until this receipt (or a real defect-class sweep)
11
+ * exists; the reader validates the same shape.
12
+ */
13
+ import { createSwarmTool } from './create-tool';
14
+ export declare function executeRecordRecurrenceSweep(args: unknown, directory: string, context?: {
15
+ sessionID?: string;
16
+ }): Promise<string>;
17
+ export declare const record_recurrence_sweep: ReturnType<typeof createSwarmTool>;
@@ -35,6 +35,14 @@ declare const StageACheckSchema: z.ZodObject<{
35
35
  feedback_item_id: z.ZodString;
36
36
  target: z.ZodString;
37
37
  expected_behavior: z.ZodString;
38
+ proof_kind: z.ZodEnum<{
39
+ conflict: "conflict";
40
+ metadata: "metadata";
41
+ defect: "defect";
42
+ "source-proof": "source-proof";
43
+ ci: "ci";
44
+ "user-decision": "user-decision";
45
+ }>;
38
46
  }, z.core.$strict>>>;
39
47
  working_directory: z.ZodOptional<z.ZodString>;
40
48
  obligation_id: z.ZodOptional<z.ZodString>;
@@ -82,6 +82,12 @@ export interface SavePlanArgs {
82
82
  * Omit to leave the current profile unchanged.
83
83
  */
84
84
  execution_profile?: Partial<ExecutionProfile>;
85
+ /**
86
+ * Narrow recovery mode for stale plan.json projections whose ledger replay
87
+ * previously failed. When true, save_plan will only accept an unchanged
88
+ * semantic re-save that reconverges plan.json with the authoritative ledger.
89
+ */
90
+ reconcile_ledger_projection?: boolean;
85
91
  }
86
92
  /**
87
93
  * Result from executing save_plan
@@ -115,6 +121,8 @@ interface RequirementCoverageResult {
115
121
  missing: RequirementCoverageEntry[];
116
122
  blocking_missing: RequirementCoverageEntry[];
117
123
  }
124
+ export declare function isLedgerProjectionReconcileRequest(args: Pick<SavePlanArgs, 'reconcile_ledger_projection'>): boolean;
125
+ export declare function isPureLedgerProjectionReconcileRequest(args: SavePlanArgs): boolean;
118
126
  /**
119
127
  * Detect template placeholder content (e.g., [task], [Project], [description], [N]).
120
128
  * These patterns indicate the LLM reproduced template examples literally rather than
@@ -8,23 +8,23 @@ export declare const ArgsSchema: z.ZodObject<{
8
8
  verdicts: z.ZodArray<z.ZodObject<{
9
9
  agent: z.ZodEnum<{
10
10
  reviewer: "reviewer";
11
- test_engineer: "test_engineer";
11
+ critic: "critic";
12
12
  explorer: "explorer";
13
+ test_engineer: "test_engineer";
13
14
  sme: "sme";
14
- critic: "critic";
15
15
  }>;
16
16
  verdict: z.ZodEnum<{
17
17
  APPROVE: "APPROVE";
18
- REJECT: "REJECT";
19
18
  CONCERNS: "CONCERNS";
19
+ REJECT: "REJECT";
20
20
  }>;
21
21
  confidence: z.ZodNumber;
22
22
  findings: z.ZodArray<z.ZodObject<{
23
23
  severity: z.ZodEnum<{
24
- LOW: "LOW";
25
- MEDIUM: "MEDIUM";
26
- HIGH: "HIGH";
27
24
  CRITICAL: "CRITICAL";
25
+ HIGH: "HIGH";
26
+ MEDIUM: "MEDIUM";
27
+ LOW: "LOW";
28
28
  }>;
29
29
  category: z.ZodString;
30
30
  location: z.ZodString;