opencode-swarm 7.119.0 → 7.121.0

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 (75) hide show
  1. package/dist/cli/{config-doctor-p73yfdz0.js → config-doctor-404c8mf8.js} +3 -3
  2. package/dist/cli/config-fingerprint-v22xh5a2.js +10 -0
  3. package/dist/cli/{core-gf1t2jmn.js → core-xnwasfpc.js} +1 -1
  4. package/dist/cli/curation-policy-re2kaysb.js +25 -0
  5. package/dist/cli/{curator-5xfkejsq.js → curator-8m0pf9cz.js} +30 -23
  6. package/dist/cli/{curator-drift-nn71xfz6.js → curator-drift-6b2fjsgr.js} +3 -2
  7. package/dist/cli/curator-llm-factory-jta9tggm.js +50 -0
  8. package/dist/cli/{evidence-summary-service-cy3k37je.js → evidence-summary-service-jtx5q3r6.js} +9 -7
  9. package/dist/cli/{gate-evidence-j2m4cd85.js → gate-evidence-tbpezk28.js} +5 -5
  10. package/dist/cli/guardrail-explain-nsfm5ksb.js +51 -0
  11. package/dist/cli/{guardrail-log-qjqgg7pz.js → guardrail-log-dhpp0kmn.js} +4 -4
  12. package/dist/cli/{hive-promoter-03m8pwg6.js → hive-promoter-8303gnfk.js} +30 -23
  13. package/dist/cli/index-0e1v02hq.js +343 -0
  14. package/dist/cli/{index-jbdgpqpj.js → index-0k4r8111.js} +28 -10
  15. package/dist/cli/index-0mbmfmt0.js +349 -0
  16. package/dist/cli/{index-5bcrp3bc.js → index-22e127jw.js} +3 -3
  17. package/dist/cli/{index-pjhfe7c3.js → index-3366gs26.js} +43 -7
  18. package/dist/cli/{index-7pspktns.js → index-3je67dcz.js} +2 -2
  19. package/dist/cli/{index-wpgv6hht.js → index-3jvqw5hy.js} +13 -26
  20. package/dist/cli/{index-05ee8pws.js → index-3ygv9535.js} +32 -25
  21. package/dist/cli/{index-bfwt3abw.js → index-4rhcth7a.js} +1 -1
  22. package/dist/cli/{index-n6fa2hhk.js → index-51gg9947.js} +1 -1
  23. package/dist/cli/index-69ms9ny1.js +261 -0
  24. package/dist/cli/{index-42cx6g2h.js → index-76kvm9z5.js} +1 -1
  25. package/dist/cli/{index-r2ysfdet.js → index-78b192v7.js} +7 -7
  26. package/dist/cli/{index-vwvkpg0d.js → index-816rkp4y.js} +3 -92
  27. package/dist/cli/index-89s4mhmw.js +6 -0
  28. package/dist/cli/index-9xpgytj9.js +386 -0
  29. package/dist/cli/index-ae75rja9.js +26 -0
  30. package/dist/cli/index-fndvr7fr.js +135 -0
  31. package/dist/cli/{index-mr3pnc4h.js → index-gmc34yzt.js} +1926 -2005
  32. package/dist/cli/index-gnp9x6se.js +93 -0
  33. package/dist/cli/{index-0pfqcjp6.js → index-h07wn84h.js} +1 -1
  34. package/dist/cli/{index-p45sshb5.js → index-j5xv8zbp.js} +17 -352
  35. package/dist/cli/{index-g2wrs7jy.js → index-kyvg2cmp.js} +1 -1
  36. package/dist/cli/{index-5hze8ztj.js → index-nhgw7de8.js} +7 -5
  37. package/dist/cli/{index-abjjn4yh.js → index-qg11yf8q.js} +4 -4
  38. package/dist/cli/index-rtry5xyf.js +27 -0
  39. package/dist/cli/{index-qx5z58a7.js → index-rywkdacj.js} +93 -11
  40. package/dist/cli/{index-pdk1n8yh.js → index-tftv9xh9.js} +44 -2
  41. package/dist/cli/{index-11q1t6g0.js → index-vqcgmy4y.js} +1 -1
  42. package/dist/cli/{index-q4kgsvdd.js → index-wtn8wf7h.js} +1 -1
  43. package/dist/cli/{index-bcg89pt8.js → index-zvae4m8g.js} +1 -1
  44. package/dist/cli/index.js +30 -23
  45. package/dist/cli/{knowledge-escalator-gt1q632m.js → knowledge-escalator-0ejqs8c9.js} +9 -8
  46. package/dist/cli/{knowledge-events-0bjdtdsb.js → knowledge-events-wx9e37ba.js} +6 -5
  47. package/dist/cli/knowledge-link-sy85fw3w.js +37 -0
  48. package/dist/cli/{knowledge-store-fm2300xf.js → knowledge-store-rnajx33a.js} +17 -6
  49. package/dist/cli/{knowledge-validator-91kx3eqv.js → knowledge-validator-1f4mkzmc.js} +11 -7
  50. package/dist/cli/{pending-delegations-9cn17983.js → pending-delegations-0z3znsec.js} +5 -5
  51. package/dist/cli/{pr-subscriptions-8a6jwek2.js → pr-subscriptions-x653151h.js} +4 -4
  52. package/dist/cli/scan-cursor-qapm0sxj.js +25 -0
  53. package/dist/cli/{schema-7c484wjz.js → schema-vwxpsk6j.js} +2 -2
  54. package/dist/cli/{scope-persistence-fm0gzhnk.js → scope-persistence-mfr36yc9.js} +2 -2
  55. package/dist/cli/{skill-generator-3f8dqjj2.js → skill-generator-tkv7s12g.js} +12 -9
  56. package/dist/config/schema.d.ts +8 -8
  57. package/dist/config/skill-mirrors.d.ts +1 -1
  58. package/dist/hooks/curator-postmortem.d.ts +6 -4
  59. package/dist/hooks/curator.d.ts +5 -1
  60. package/dist/hooks/hive-promoter.d.ts +3 -1
  61. package/dist/hooks/knowledge-store.d.ts +54 -1
  62. package/dist/hooks/knowledge-types.d.ts +107 -2
  63. package/dist/hooks/knowledge-validator.d.ts +25 -4
  64. package/dist/index.js +387 -384
  65. package/dist/knowledge/curation-policy.d.ts +125 -0
  66. package/dist/knowledge/family-manifest.d.ts +30 -2
  67. package/dist/knowledge/family-migration.d.ts +16 -4
  68. package/dist/knowledge/scan-cursor.d.ts +107 -0
  69. package/dist/knowledge/worktree-identity.d.ts +39 -0
  70. package/dist/memory/schema.d.ts +1 -1
  71. package/dist/services/knowledge-diagnostics.d.ts +29 -0
  72. package/package.json +1 -1
  73. package/dist/cli/curator-llm-factory-rwwnmdvk.js +0 -43
  74. package/dist/cli/guardrail-explain-kacpc2zm.js +0 -44
  75. /package/dist/cli/{index-vvk2g744.js → index-7g4c7s5r.js} +0 -0
@@ -33,19 +33,22 @@ import {
33
33
  sanitizeSlug,
34
34
  selectCandidateEntries,
35
35
  writeEvalStub
36
- } from "./index-r2ysfdet.js";
37
- import"./index-pjhfe7c3.js";
38
- import"./index-5hze8ztj.js";
39
- import"./index-qx5z58a7.js";
40
- import"./index-bfwt3abw.js";
41
- import"./index-wpgv6hht.js";
36
+ } from "./index-78b192v7.js";
37
+ import"./index-3366gs26.js";
38
+ import"./index-69ms9ny1.js";
39
+ import"./index-rtry5xyf.js";
40
+ import"./index-rywkdacj.js";
41
+ import"./index-nhgw7de8.js";
42
+ import"./index-ae75rja9.js";
43
+ import"./index-3jvqw5hy.js";
44
+ import"./index-4rhcth7a.js";
42
45
  import"./index-ye3fndsw.js";
43
46
  import"./index-zgwm4ryv.js";
44
- import"./index-0pfqcjp6.js";
45
- import"./index-42cx6g2h.js";
47
+ import"./index-h07wn84h.js";
48
+ import"./index-76kvm9z5.js";
46
49
  import"./index-fsrp8wp3.js";
47
50
  import"./index-q2rrv0cy.js";
48
- import"./index-vvk2g744.js";
51
+ import"./index-7g4c7s5r.js";
49
52
  import"./index-qe3v54nb.js";
50
53
  import"./index-a76rekgs.js";
51
54
  export {
@@ -616,9 +616,9 @@ export declare const KnowledgeConfigSchema: z.ZodObject<{
616
616
  todo_max_phases: z.ZodDefault<z.ZodNumber>;
617
617
  sweep_enabled: z.ZodDefault<z.ZodBoolean>;
618
618
  confidence_floor_action: z.ZodDefault<z.ZodEnum<{
619
- none: "none";
620
- demote: "demote";
621
619
  quarantine: "quarantine";
620
+ demote: "demote";
621
+ none: "none";
622
622
  }>>;
623
623
  confidence_floor_min_outcomes: z.ZodDefault<z.ZodNumber>;
624
624
  confidence_floor_signal_threshold: z.ZodDefault<z.ZodNumber>;
@@ -1386,9 +1386,9 @@ export declare const ExternalSkillCandidateSourceTypeSchema: z.ZodEnum<{
1386
1386
  export type ExternalSkillCandidateSourceType = z.infer<typeof ExternalSkillCandidateSourceTypeSchema>;
1387
1387
  /** Evaluation verdict for an external skill candidate. */
1388
1388
  export declare const ExternalSkillCandidateEvaluationVerdictSchema: z.ZodEnum<{
1389
+ pending: "pending";
1389
1390
  promoted: "promoted";
1390
1391
  quarantined: "quarantined";
1391
- pending: "pending";
1392
1392
  in_review: "in_review";
1393
1393
  passed: "passed";
1394
1394
  rejected: "rejected";
@@ -1433,9 +1433,9 @@ export declare const ExternalSkillCandidateSchema: z.ZodObject<{
1433
1433
  skill_body: z.ZodString;
1434
1434
  risk_flags: z.ZodDefault<z.ZodArray<z.ZodString>>;
1435
1435
  evaluation_verdict: z.ZodDefault<z.ZodEnum<{
1436
+ pending: "pending";
1436
1437
  promoted: "promoted";
1437
1438
  quarantined: "quarantined";
1438
- pending: "pending";
1439
1439
  in_review: "in_review";
1440
1440
  passed: "passed";
1441
1441
  rejected: "rejected";
@@ -1443,9 +1443,9 @@ export declare const ExternalSkillCandidateSchema: z.ZodObject<{
1443
1443
  }>>;
1444
1444
  evaluation_history: z.ZodDefault<z.ZodArray<z.ZodObject<{
1445
1445
  verdict: z.ZodEnum<{
1446
+ pending: "pending";
1446
1447
  promoted: "promoted";
1447
1448
  quarantined: "quarantined";
1448
- pending: "pending";
1449
1449
  in_review: "in_review";
1450
1450
  passed: "passed";
1451
1451
  rejected: "rejected";
@@ -1456,9 +1456,9 @@ export declare const ExternalSkillCandidateSchema: z.ZodObject<{
1456
1456
  reason: z.ZodOptional<z.ZodString>;
1457
1457
  candidate_id: z.ZodOptional<z.ZodString>;
1458
1458
  original_verdict: z.ZodOptional<z.ZodEnum<{
1459
+ pending: "pending";
1459
1460
  promoted: "promoted";
1460
1461
  quarantined: "quarantined";
1461
- pending: "pending";
1462
1462
  in_review: "in_review";
1463
1463
  passed: "passed";
1464
1464
  rejected: "rejected";
@@ -1928,9 +1928,9 @@ export declare const PluginConfigSchema: z.ZodObject<{
1928
1928
  todo_max_phases: z.ZodDefault<z.ZodNumber>;
1929
1929
  sweep_enabled: z.ZodDefault<z.ZodBoolean>;
1930
1930
  confidence_floor_action: z.ZodDefault<z.ZodEnum<{
1931
- none: "none";
1932
- demote: "demote";
1933
1931
  quarantine: "quarantine";
1932
+ demote: "demote";
1933
+ none: "none";
1934
1934
  }>>;
1935
1935
  confidence_floor_min_outcomes: z.ZodDefault<z.ZodNumber>;
1936
1936
  confidence_floor_signal_threshold: z.ZodDefault<z.ZodNumber>;
@@ -92,7 +92,7 @@ export declare const OPENCODE_ONLY_ARCHITECT_MODE_SKILLS: Array<{
92
92
  */
93
93
  export declare const ADDITIONAL_SKILL_MIRROR_CONTRACTS: Array<{
94
94
  slug: string;
95
- kind: 'identical' | 'divergent' | 'opencode-only' | 'adapter';
95
+ kind: 'identical' | 'divergent' | 'opencode-only' | 'adapter' | 'agents-only';
96
96
  canonical?: '.claude' | '.opencode';
97
97
  extraIdenticalPaths?: string[];
98
98
  /**
@@ -67,9 +67,11 @@ export interface PostMortemActionResult {
67
67
  proposals_rejected: number;
68
68
  proposals_skipped: number;
69
69
  }
70
- declare function collectKnowledgeSummary(directory: string, scope?: 'session' | 'project', sessionID?: string): Promise<KnowledgeEventSummary[]>;
70
+ declare function collectKnowledgeSummary(directory: string, scope?: 'session' | 'project', sessionID?: string, out?: {
71
+ generation?: number;
72
+ }): Promise<KnowledgeEventSummary[]>;
71
73
  declare function parsePostMortemActions(llmOutput: string): ParsedPostMortemActions;
72
- declare function executePostMortemActions(directory: string, parsed: ParsedPostMortemActions, options: PostMortemOptions): Promise<{
74
+ declare function executePostMortemActions(directory: string, parsed: ParsedPostMortemActions, options: PostMortemOptions, generation?: number): Promise<{
73
75
  result: PostMortemActionResult;
74
76
  warnings: string[];
75
77
  }>;
@@ -131,8 +133,8 @@ export declare const _internals: {
131
133
  executePostMortemActions: typeof executePostMortemActions;
132
134
  verifyPostMortemKnowledgeActions: typeof verifyPostMortemKnowledgeActions;
133
135
  repairPostMortemActions: typeof repairPostMortemActions;
134
- loadDefaultKnowledgeConfig: () => Promise<KnowledgeConfig>;
135
- applyCuratorKnowledgeUpdates: (directory: string, recommendations: KnowledgeRecommendation[], knowledgeConfig: KnowledgeConfig) => Promise<{
136
+ loadDefaultKnowledgeConfig: (directory: string) => Promise<KnowledgeConfig>;
137
+ applyCuratorKnowledgeUpdates: (directory: string, recommendations: KnowledgeRecommendation[], knowledgeConfig: KnowledgeConfig, generation?: number) => Promise<{
136
138
  applied: number;
137
139
  skipped: number;
138
140
  }>;
@@ -213,9 +213,13 @@ export declare function runCuratorPhase(directory: string, phase: number, agents
213
213
  * @param directory - The workspace directory
214
214
  * @param recommendations - Array of knowledge recommendations to apply
215
215
  * @param knowledgeConfig - Knowledge configuration (for path resolution)
216
+ * @param generation - Optional fair-scan-cursor generation (#1848 §4). When
217
+ * provided, curation mutations stamp `last_curated_generation` on the mutated
218
+ * entry so a future sweep can detect it was already curated this generation.
219
+ * When undefined, no stamp is written (preserves callers that don't pass it).
216
220
  * @returns Counts of applied and skipped recommendations
217
221
  */
218
- export declare function applyCuratorKnowledgeUpdates(directory: string, recommendations: KnowledgeRecommendation[], knowledgeConfig: KnowledgeConfig): Promise<{
222
+ export declare function applyCuratorKnowledgeUpdates(directory: string, recommendations: KnowledgeRecommendation[], knowledgeConfig: KnowledgeConfig, generation?: number): Promise<{
219
223
  applied: number;
220
224
  skipped: number;
221
225
  }>;
@@ -22,6 +22,7 @@
22
22
  * runs only on the lazy `/swarm promote`, close, curate, and postmortem paths.
23
23
  */
24
24
  import { resolveCohortId } from '../knowledge/cohort-identity.js';
25
+ import { authorizeCuration } from '../knowledge/curation-policy.js';
25
26
  import { appendCuratorRecommendation, readCuratorSummary } from './curator.js';
26
27
  import { transactHiveStore } from './hive-transaction.js';
27
28
  import type { KnowledgeConfig, ProjectConfirmationRecord, PromotionEvidenceRecord, SwarmKnowledgeEntry } from './knowledge-types.js';
@@ -79,6 +80,7 @@ export declare const _internals: {
79
80
  resolveCohortId: typeof resolveCohortId;
80
81
  transactHiveStore: typeof transactHiveStore;
81
82
  validateLesson: typeof validateLesson;
83
+ authorizeCuration: typeof authorizeCuration;
82
84
  /** Loads validated terminal-application evidence per swarm entry id. Empty
83
85
  * until #1849 produces real receipts (conservative: no synthetic credit). */
84
86
  loadPromotionEvidence: (_swarmEntries: SwarmKnowledgeEntry[]) => Promise<Record<string, PromotionEvidenceRecord[]>>;
@@ -113,7 +115,7 @@ export declare const _internals: {
113
115
  default_max_phases: number;
114
116
  todo_max_phases: number;
115
117
  sweep_enabled: boolean;
116
- confidence_floor_action: "none" | "demote" | "quarantine";
118
+ confidence_floor_action: "quarantine" | "demote" | "none";
117
119
  confidence_floor_min_outcomes: number;
118
120
  confidence_floor_signal_threshold: number;
119
121
  contradiction_threshold_action: "quarantine" | "tag_only";
@@ -1,10 +1,11 @@
1
1
  /** Core storage layer for the opencode-swarm v6.17 two-tier knowledge system. */
2
2
  import { resolveHiveDataDir, resolveHiveEventsPath as resolveHiveEventsPathImpl, resolveHiveKnowledgePath as resolveHiveKnowledgePathImpl, resolveHiveRejectedPath as resolveHiveRejectedPathImpl } from '../knowledge/hive-paths.js';
3
- import type { KnowledgeEntryBase, RejectedLesson, RetrievalOutcome } from './knowledge-types.js';
3
+ import type { KnowledgeEntryBase, RejectedLesson, RetrievalOutcome, RewriteHistoryRecord } from './knowledge-types.js';
4
4
  export declare function getPlatformConfigDir(): string;
5
5
  export declare function resolveSwarmKnowledgePath(directory: string): string;
6
6
  export declare function resolveSwarmRejectedPath(directory: string): string;
7
7
  export declare function resolveSwarmRetractionsPath(directory: string): string;
8
+ export declare function resolveRewriteHistoryPath(directory: string): string;
8
9
  export declare const resolveHiveKnowledgePath: typeof resolveHiveKnowledgePathImpl;
9
10
  export declare const resolveHiveRejectedPath: typeof resolveHiveRejectedPathImpl;
10
11
  export declare const resolveHiveEventsPath: typeof resolveHiveEventsPathImpl;
@@ -12,6 +13,12 @@ export { resolveHiveDataDir };
12
13
  declare function parseKnowledgeContent<T>(content: string, max: number): T[];
13
14
  export declare function readKnowledge<T>(filePath: string, maxEntries?: number): Promise<T[]>;
14
15
  export declare function normalizeEntry<T>(raw: T): T;
16
+ /**
17
+ * Compute a 12-hex SHA-256 prefix of a lesson string (issue #1848 §3).
18
+ * Used as the `content_hash` CAS token, stamped at write/mutation time only.
19
+ * Mirrors the style of `lessonRevision()` in hive-promoter.ts.
20
+ */
21
+ export declare function computeContentHash(lesson: string): string;
15
22
  export declare function readRejectedLessons(directory: string): Promise<RejectedLesson[]>;
16
23
  export interface KnowledgeRetractionRecord {
17
24
  id: string;
@@ -24,10 +31,56 @@ export interface KnowledgeRetractionRecord {
24
31
  }
25
32
  export declare function readRetractionRecords(directory: string): Promise<KnowledgeRetractionRecord[]>;
26
33
  export declare function appendRetractionRecord(directory: string, record: KnowledgeRetractionRecord): Promise<void>;
34
+ /**
35
+ * Append an immutable rewrite/merge history record to the cohort-scoped audit
36
+ * log (issue #1848 §3). FIFO-capped at 2000 entries so the audit trail is
37
+ * bounded. Fail-open: a history-append failure must not abort the mutation that
38
+ * already committed (the mutation is the source of truth; history is audit).
39
+ */
40
+ export declare function appendRewriteHistory(directory: string, record: RewriteHistoryRecord): Promise<void>;
41
+ /**
42
+ * Read rewrite/merge history records (issue #1848 §3). Used for audit/recovery.
43
+ */
44
+ export declare function readRewriteHistory(directory: string): Promise<RewriteHistoryRecord[]>;
27
45
  export declare function appendKnowledge<T>(filePath: string, entry: T): Promise<void>;
28
46
  export declare function rewriteKnowledge<T>(filePath: string, entries: T[]): Promise<void>;
29
47
  export declare function transactFile<T>(filePath: string, read: (filePath: string) => Promise<T>, write: (filePath: string, data: T) => Promise<void>, mutate: (data: T) => T | null): Promise<boolean>;
30
48
  export declare function transactKnowledge<T>(filePath: string, mutate: (entries: T[]) => T[] | null): Promise<boolean>;
49
+ /**
50
+ * Compare-and-swap guarded mutation for a single entry (issue #1848 §3).
51
+ *
52
+ * Runs inside the existing directory lock (lock-before-read). Finds the entry
53
+ * by `id`. If `expectedRevision`/`expectedContentHash` are provided and the
54
+ * current entry's revision/content_hash do not match, the mutation is SKIPPED
55
+ * and `{committed:false, casFailed:true}` is returned — a stale curator plan is
56
+ * rejected, NOT silently applied. This closes the lost-update hazard where a
57
+ * plan generated from a stale snapshot overwrites an entry a sibling worktree
58
+ * just updated.
59
+ *
60
+ * On an accepted mutation: bumps `revision`, recomputes `content_hash`, stamps
61
+ * `updated_at`, and (when `apply` returns a `RewriteHistoryRecord`) appends the
62
+ * immutable before/after audit record. Authorization is the CALLER's
63
+ * responsibility (run `authorizeCuration` BEFORE calling this); CAS enforces
64
+ * the revision contract INSIDE the transaction.
65
+ *
66
+ * Legacy entry (revision 0/undefined): CAS with `expectedRevision === undefined`
67
+ * is allowed (the first authorized mutation stamps revision 1). The
68
+ * unknown-owner-protected case never reaches here because authorizeCuration
69
+ * returns a proposal instead of authorizing.
70
+ */
71
+ export declare function transactKnowledgeWithCas<T extends {
72
+ id: string;
73
+ revision?: number;
74
+ content_hash?: string;
75
+ lesson?: string;
76
+ updated_at?: string;
77
+ }>(directory: string, filePath: string, entryId: string, expectedRevision: number | undefined, expectedContentHash: string | undefined, apply: (entry: T) => {
78
+ mutated: T;
79
+ rewriteHistory?: RewriteHistoryRecord;
80
+ } | null): Promise<{
81
+ committed: boolean;
82
+ casFailed: boolean;
83
+ }>;
31
84
  export declare function getArchivedKnowledgeIds(directory: string): Promise<Set<string>>;
32
85
  export declare function appendKnowledgeWithCapEnforcement<T>(filePath: string, entry: T, maxEntries: number): Promise<boolean>;
33
86
  export declare function enforceKnowledgeCap<T>(filePath: string, maxEntries: number): Promise<void>;
@@ -120,6 +120,87 @@ export interface ActionableDirectiveFields {
120
120
  /** ISO 8601 timestamp of last explicit acknowledgment. */
121
121
  last_acknowledged_at?: string;
122
122
  }
123
+ /**
124
+ * Canonical cohort-scoped producer provenance (issue #1848 §1).
125
+ *
126
+ * Every mutable knowledge entry carries enough immutable provenance for a
127
+ * cohort-safe ownership decision: who produced it, in which cohort, from which
128
+ * worktree/session, and tied to which creation transaction. Absent/null on
129
+ * legacy entries written before #1848 — such entries are treated as
130
+ * unknown-owner and protected from destructive curation by default (the
131
+ * curation-policy layer converts destructive intent into a non-destructive
132
+ * proposal rather than guessing an owner from the current worktree).
133
+ *
134
+ * `worktree_id` is the primary ownership key: a worktree may directly mutate an
135
+ * entry only when it is the proven producer (or cohort quorum / operator
136
+ * override applies). It is stored at write time from `resolveWorktreeId`
137
+ * (src/knowledge/worktree-identity.ts) — a per-worktree stable id, NOT
138
+ * link-resolved, so two sibling worktrees of the same cohort have distinct
139
+ * ownership keys.
140
+ */
141
+ export interface ProducerProvenance {
142
+ /** Canonical cohort id (from `resolveCohortId`, #1846). Scopes quorum + audit. */
143
+ cohort_id: string;
144
+ /** Stable per-worktree id (owner key). NOT link-resolved — per-worktree. */
145
+ worktree_id: string;
146
+ /** Producing session id, when known (audit). */
147
+ session_id?: string;
148
+ /** Producing agent/role, when known (audit). */
149
+ role?: string;
150
+ /** Creation transaction/event id, when known (audit lineage). */
151
+ creation_event_id?: string;
152
+ }
153
+ /**
154
+ * The evidence scope a curation decision was based on (issue #1848 §2).
155
+ *
156
+ * Absence of LOCAL session events is NOT negative evidence — a worktree that
157
+ * never saw an application event for an entry cannot conclude the entry was
158
+ * never applied (a sibling producer may have applied it). Evidence queries must
159
+ * be scoped intentionally:
160
+ * - `local-session`: only this worktree's session events (owner-local decisions)
161
+ * - `producer`: the producing worktree's own validated evidence
162
+ * - `cohort-wide`: the full cohort event log (shared/quorum decisions)
163
+ */
164
+ export type CurationEvidenceScope = 'local-session' | 'producer' | 'cohort-wide';
165
+ /**
166
+ * Every destructive lifecycle action the curation-policy layer authorizes
167
+ * (issue #1848 §2). All of these share one policy so archive/purge/remove/
168
+ * quarantine/retraction/merge/retire cannot diverge in ownership semantics.
169
+ */
170
+ export type CurationAction = 'archive' | 'purge' | 'remove' | 'quarantine' | 'retract' | 'rewrite' | 'merge' | 'retire' | 'demote' | 'restore' | 'unarchive' | 'escalate';
171
+ /**
172
+ * A non-destructive proposal recorded when a destructive curation action is
173
+ * unauthorized (issue #1848 §2). Other cohort members may later confirm it.
174
+ * Destructive intent is preserved WITHOUT mutating the shared record.
175
+ */
176
+ export interface CurationProposal {
177
+ entryId: string;
178
+ action: CurationAction;
179
+ reason?: string;
180
+ evidenceScope: CurationEvidenceScope;
181
+ proposedAt: string;
182
+ status: 'pending';
183
+ }
184
+ /**
185
+ * Immutable before/after history for a destructive rewrite or merge (issue
186
+ * #1848 §3). Ensures the only copy of prior lesson text is never overwritten,
187
+ * and supports deterministic reconstruction or rollback. Appended to the
188
+ * cohort-scoped `knowledge-rewrites.jsonl` audit log.
189
+ */
190
+ export interface RewriteHistoryRecord {
191
+ entry_id: string;
192
+ before_lesson: string;
193
+ after_lesson: string;
194
+ before_revision: number;
195
+ after_revision: number;
196
+ /** 'auto' | producing worktree_id | 'manual-override'. */
197
+ actor: string;
198
+ reason?: string;
199
+ /** Event/trace ids that justified the change. */
200
+ evidence_refs?: string[];
201
+ timestamp: string;
202
+ action: 'rewrite' | 'merge';
203
+ }
123
204
  export interface KnowledgeEntryBase extends ActionableDirectiveFields {
124
205
  id: string;
125
206
  tier: 'swarm' | 'hive';
@@ -163,9 +244,33 @@ export interface KnowledgeEntryBase extends ActionableDirectiveFields {
163
244
  * counter update. Prevents double-counting when `curateAndStoreSwarm` runs
164
245
  * multiple times in the same logical phase (e.g. phase-complete + close). */
165
246
  last_demotion_phase?: number;
247
+ /** #1848 §1: producer provenance. Absent/null on legacy entries →
248
+ * unknown-owner → protected from destructive curation by default. Filled at
249
+ * creation time by all new-entry paths via `resolveWorktreeId` +
250
+ * `resolveCohortId`. Never synthesized for legacy records. */
251
+ producer?: ProducerProvenance | null;
252
+ /** #1848 §3: monotonic revision counter for compare-and-swap. Starts at 1
253
+ * at creation, bumped on each accepted mutation. Absent/0 = legacy (CAS
254
+ * with `expectedRevision === undefined` allows the first mutation). */
255
+ revision?: number;
256
+ /** #1848 §3: 12-hex SHA-256 prefix of `lesson`, for CAS content verification.
257
+ * Computed at WRITE time only (never per-read) to avoid hashing thousands of
258
+ * entries on every readKnowledge of a large cohort store. Absent on legacy. */
259
+ content_hash?: string;
260
+ /** #1848 §4: idempotency stamp for the fair scan cursor. Records the
261
+ * generation in which this entry was last curated by a non-idempotent action
262
+ * (rewrite/demote/confidence-delta). Prevents compounding under concurrent
263
+ * cohort postmortems that claim the same batch. */
264
+ last_curated_generation?: number;
166
265
  }
167
- /** v2 schema marker. v1 entries are still parseable and normalized in-memory by knowledge-store.normalizeEntry. */
168
- export declare const KNOWLEDGE_SCHEMA_VERSION = 2;
266
+ /**
267
+ * Current knowledge schema marker. v1 entries are still parseable and
268
+ * normalized in-memory by knowledge-store.normalizeEntry. v3 (#1848) adds
269
+ * optional `producer`, `revision`, `content_hash`, and `last_curated_generation`
270
+ * fields — all default-absent so v1/v2/v3 records coexist on disk without an
271
+ * on-disk migration. New writes stamp v3.
272
+ */
273
+ export declare const KNOWLEDGE_SCHEMA_VERSION = 3;
169
274
  /**
170
275
  * The single canonical set of inactive (non-retrieval) knowledge statuses.
171
276
  * Every retrieval/filter consumer MUST go through {@link isActiveStatus} rather
@@ -1,4 +1,5 @@
1
1
  /** Three-layer validation gate for the opencode-swarm v6.17 knowledge system. */
2
+ import { type CurationAuthorizationInput, type CurationContext } from '../knowledge/curation-policy.js';
2
3
  import type { ActionableDirectiveFields, DirectivePriority, KnowledgeCategory, KnowledgeEntryBase } from './knowledge-types.js';
3
4
  export interface ValidationResult {
4
5
  valid: boolean;
@@ -124,12 +125,27 @@ export interface EntryHealthResult {
124
125
  concern?: string;
125
126
  }
126
127
  export declare function auditEntryHealth(entry: KnowledgeEntryBase): EntryHealthResult;
127
- export declare function quarantineEntry(directory: string, entryId: string, reason: string, reportedBy: 'architect' | 'user' | 'auto'): Promise<void>;
128
- export declare function restoreEntry(directory: string, entryId: string): Promise<void>;
128
+ export declare function quarantineEntry(directory: string, entryId: string, reason: string, reportedBy: 'architect' | 'user' | 'auto',
129
+ /** #1848: cohort-safe curation context. When provided, the quarantine is
130
+ * authorized through the shared curation policy BEFORE mutating; an
131
+ * unauthorized action becomes a non-destructive no-op (the policy records a
132
+ * proposal). When omitted, the legacy behavior applies (used by
133
+ * deterministic validation-failure withholds and non-cohort callers). */
134
+ curationContext?: {
135
+ input: CurationAuthorizationInput;
136
+ context: CurationContext;
137
+ }): Promise<void>;
138
+ export declare function restoreEntry(directory: string, entryId: string,
139
+ /** #1848 §2: cohort-safe curation context (optional). When provided, the
140
+ * restore is authorized through the shared policy before mutating. */
141
+ curationContext?: {
142
+ input: CurationAuthorizationInput;
143
+ context: CurationContext;
144
+ }): Promise<void>;
129
145
  export interface UnarchiveResult {
130
146
  restored: boolean;
131
147
  restored_to?: string;
132
- reason?: 'not_found' | 'not_archived' | 'invalid_lesson';
148
+ reason?: 'not_found' | 'not_archived' | 'invalid_lesson' | 'blocked_by_policy';
133
149
  }
134
150
  /**
135
151
  * G6 (#1716): restore an `archived`-status entry from `knowledge.jsonl` to its
@@ -139,7 +155,12 @@ export interface UnarchiveResult {
139
155
  * (especially one restored to `promoted`) is not demoted almost immediately
140
156
  * under the new demotion window.
141
157
  */
142
- export declare function unarchiveEntry(directory: string, entryId: string): Promise<UnarchiveResult>;
158
+ export declare function unarchiveEntry(directory: string, entryId: string,
159
+ /** #1848 §2 (IR-3 fix): cohort-safe curation context (optional). */
160
+ curationContext?: {
161
+ input: CurationAuthorizationInput;
162
+ context: CurationContext;
163
+ }): Promise<UnarchiveResult>;
143
164
  export declare const _internals: {
144
165
  validateLesson: typeof validateLesson;
145
166
  auditEntryHealth: typeof auditEntryHealth;