@guyghost/swarm-dao-core 0.16.2 → 1.0.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 (109) hide show
  1. package/dist/adapters/persistence/file-dao-state.repository.d.ts +35 -0
  2. package/dist/adapters/persistence/file-dao-state.repository.d.ts.map +1 -1
  3. package/dist/adapters/persistence/file-dao-state.repository.js +316 -30
  4. package/dist/adapters/persistence/file-dao-state.repository.js.map +1 -1
  5. package/dist/adapters/ship-audit/fs-ship-audit.store.d.ts.map +1 -1
  6. package/dist/adapters/ship-audit/fs-ship-audit.store.js +57 -2
  7. package/dist/adapters/ship-audit/fs-ship-audit.store.js.map +1 -1
  8. package/dist/application/proposals/control-proposal.use-case.d.ts +2 -1
  9. package/dist/application/proposals/control-proposal.use-case.d.ts.map +1 -1
  10. package/dist/application/proposals/control-proposal.use-case.js +16 -3
  11. package/dist/application/proposals/control-proposal.use-case.js.map +1 -1
  12. package/dist/application/proposals/create-proposal.use-case.d.ts.map +1 -1
  13. package/dist/application/proposals/create-proposal.use-case.js +22 -0
  14. package/dist/application/proposals/create-proposal.use-case.js.map +1 -1
  15. package/dist/application/proposals/deliberate-proposal.use-case.d.ts +4 -0
  16. package/dist/application/proposals/deliberate-proposal.use-case.d.ts.map +1 -1
  17. package/dist/application/proposals/deliberate-proposal.use-case.js +33 -13
  18. package/dist/application/proposals/deliberate-proposal.use-case.js.map +1 -1
  19. package/dist/application/proposals/record-deliberation-outputs.use-case.d.ts.map +1 -1
  20. package/dist/application/proposals/record-deliberation-outputs.use-case.js +16 -2
  21. package/dist/application/proposals/record-deliberation-outputs.use-case.js.map +1 -1
  22. package/dist/application/proposals/reject-proposal.use-case.d.ts +3 -3
  23. package/dist/application/proposals/reject-proposal.use-case.d.ts.map +1 -1
  24. package/dist/application/proposals/reject-proposal.use-case.js +6 -4
  25. package/dist/application/proposals/reject-proposal.use-case.js.map +1 -1
  26. package/dist/application/proposals/ship-proposal.use-case.d.ts +1 -0
  27. package/dist/application/proposals/ship-proposal.use-case.d.ts.map +1 -1
  28. package/dist/application/proposals/ship-proposal.use-case.js +31 -4
  29. package/dist/application/proposals/ship-proposal.use-case.js.map +1 -1
  30. package/dist/commands/registry.js +3 -3
  31. package/dist/commands/registry.js.map +1 -1
  32. package/dist/config.d.ts +9 -1
  33. package/dist/config.d.ts.map +1 -1
  34. package/dist/config.js +184 -6
  35. package/dist/config.js.map +1 -1
  36. package/dist/control/gates.d.ts +10 -1
  37. package/dist/control/gates.d.ts.map +1 -1
  38. package/dist/control/gates.js +105 -43
  39. package/dist/control/gates.js.map +1 -1
  40. package/dist/delivery/execution-isolation.d.ts +3 -0
  41. package/dist/delivery/execution-isolation.d.ts.map +1 -1
  42. package/dist/delivery/execution-isolation.js +5 -0
  43. package/dist/delivery/execution-isolation.js.map +1 -1
  44. package/dist/governance/agents.d.ts.map +1 -1
  45. package/dist/governance/agents.js +5 -1
  46. package/dist/governance/agents.js.map +1 -1
  47. package/dist/governance/delegation.utils.d.ts +16 -0
  48. package/dist/governance/delegation.utils.d.ts.map +1 -1
  49. package/dist/governance/delegation.utils.js +68 -0
  50. package/dist/governance/delegation.utils.js.map +1 -1
  51. package/dist/governance/proposal.utils.d.ts +11 -1
  52. package/dist/governance/proposal.utils.d.ts.map +1 -1
  53. package/dist/governance/proposal.utils.js +40 -7
  54. package/dist/governance/proposal.utils.js.map +1 -1
  55. package/dist/governance/voting.d.ts +10 -2
  56. package/dist/governance/voting.d.ts.map +1 -1
  57. package/dist/governance/voting.js +41 -9
  58. package/dist/governance/voting.js.map +1 -1
  59. package/dist/host-tools/github-config.d.ts.map +1 -1
  60. package/dist/host-tools/github-config.js +14 -2
  61. package/dist/host-tools/github-config.js.map +1 -1
  62. package/dist/host-tools/handlers.d.ts +3 -0
  63. package/dist/host-tools/handlers.d.ts.map +1 -1
  64. package/dist/host-tools/handlers.js +91 -28
  65. package/dist/host-tools/handlers.js.map +1 -1
  66. package/dist/integrations/github.d.ts +1 -0
  67. package/dist/integrations/github.d.ts.map +1 -1
  68. package/dist/integrations/github.js +41 -0
  69. package/dist/integrations/github.js.map +1 -1
  70. package/dist/intelligence/index.d.ts +1 -0
  71. package/dist/intelligence/index.d.ts.map +1 -1
  72. package/dist/intelligence/index.js +1 -0
  73. package/dist/intelligence/index.js.map +1 -1
  74. package/dist/intelligence/roundtable.d.ts.map +1 -1
  75. package/dist/intelligence/roundtable.js +10 -0
  76. package/dist/intelligence/roundtable.js.map +1 -1
  77. package/dist/intelligence/runtime.d.ts +61 -0
  78. package/dist/intelligence/runtime.d.ts.map +1 -0
  79. package/dist/intelligence/runtime.js +135 -0
  80. package/dist/intelligence/runtime.js.map +1 -0
  81. package/dist/intelligence/sequential.d.ts +3 -0
  82. package/dist/intelligence/sequential.d.ts.map +1 -1
  83. package/dist/intelligence/sequential.js +30 -0
  84. package/dist/intelligence/sequential.js.map +1 -1
  85. package/dist/intelligence/swarm.d.ts +11 -1
  86. package/dist/intelligence/swarm.d.ts.map +1 -1
  87. package/dist/intelligence/swarm.js +62 -3
  88. package/dist/intelligence/swarm.js.map +1 -1
  89. package/dist/models/improvement-loop.machine.d.ts +7 -1
  90. package/dist/models/improvement-loop.machine.d.ts.map +1 -1
  91. package/dist/models/improvement-loop.machine.js +9 -1
  92. package/dist/models/improvement-loop.machine.js.map +1 -1
  93. package/dist/models/proposal.machine.d.ts +11 -0
  94. package/dist/models/proposal.machine.d.ts.map +1 -1
  95. package/dist/models/proposal.machine.js +14 -3
  96. package/dist/models/proposal.machine.js.map +1 -1
  97. package/dist/persistence.d.ts +23 -1
  98. package/dist/persistence.d.ts.map +1 -1
  99. package/dist/persistence.js +77 -38
  100. package/dist/persistence.js.map +1 -1
  101. package/dist/types/index.d.ts +12 -0
  102. package/dist/types/index.d.ts.map +1 -1
  103. package/dist/types/index.js +1 -0
  104. package/dist/types/index.js.map +1 -1
  105. package/dist/utils/host.d.ts +8 -1
  106. package/dist/utils/host.d.ts.map +1 -1
  107. package/dist/utils/host.js +25 -3
  108. package/dist/utils/host.js.map +1 -1
  109. package/package.json +2 -2
@@ -1,15 +1,50 @@
1
1
  import type { DaoStateRepositoryPort } from "../../ports/repository.js";
2
2
  import { type DAOState } from "../../types/index.js";
3
+ /**
4
+ * Repair ID counters from the maximum existing ids (issue #157). Shared by
5
+ * every load path (loadState and FileDaoStateRepository.open) so both produce
6
+ * identical, collision-free counters — e.g. a nextProposalId left behind a
7
+ * hand-edit or a restored backup no longer yields duplicate proposal ids.
8
+ */
9
+ export declare function repairCounters(state: DAOState): void;
3
10
  /** Instance-owned filesystem adapter. No process-global DAO state or write cache. */
4
11
  export declare class FileDaoStateRepository implements DaoStateRepositoryPort {
5
12
  private readonly state;
6
13
  private readonly daoRoot;
7
14
  private readonly writeCache;
15
+ private writeQueue;
16
+ /** Last state.json content this instance read or wrote, for cheap divergence checks. */
17
+ private rawStateOnDisk;
18
+ /** Revision this instance last read from, or wrote to, disk (issue #153). */
19
+ private seenRevision;
8
20
  private constructor();
21
+ /** Wrap already-loaded state so compatibility loaders share the locked persist path. */
22
+ static fromLoaded(state: DAOState, rawStateOnDisk: string | null): FileDaoStateRepository;
9
23
  static open(cwd: string): Promise<FileDaoStateRepository>;
10
24
  get(): DAOState;
11
25
  persist(): Promise<void>;
26
+ /**
27
+ * Whether persist() would write anything. Mirrors the per-file decisions in
28
+ * writeIfChanged/persistDecisions: when every serialized payload matches the
29
+ * write cache, persist is a no-op and can skip lock, check and I/O.
30
+ */
31
+ private hasPendingWrites;
32
+ /**
33
+ * Fail-fast optimistic concurrency: if another process persisted a state
34
+ * this instance has not seen, refuse to overwrite it instead of silently
35
+ * dropping votes/proposals (last-writer-wins).
36
+ *
37
+ * Returns the revision currently on disk. Two layers:
38
+ * 1. stateRevision comparison (issue #153) — catches ANY divergence,
39
+ * including votes added to a proposal known to both processes.
40
+ * 2. proposal-id/counter checks — catch hand-edited files whose revision
41
+ * was not bumped (state.json is a documented, readable format).
42
+ */
43
+ private checkNoConcurrentModification;
44
+ /** Decisions to persist: closed proposals only, ordered by id. Single source for persistDecisions and hasPendingWrites. */
45
+ private closedDecisions;
12
46
  private persistDecisions;
13
47
  private writeIfChanged;
14
48
  }
49
+ export declare function withFileLock<T>(daoRoot: string, fn: () => Promise<T>): Promise<T>;
15
50
  //# sourceMappingURL=file-dao-state.repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-dao-state.repository.d.ts","sourceRoot":"","sources":["../../../src/adapters/persistence/file-dao-state.repository.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAsB,KAAK,QAAQ,EAAuB,MAAM,sBAAsB,CAAC;AA2B9F,qFAAqF;AACrF,qBAAa,sBAAuB,YAAW,sBAAsB;IAIjE,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IAExD,OAAO;WAKa,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAc/D,GAAG,IAAI,QAAQ;IAIT,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAMvB,gBAAgB;YAyBhB,cAAc;CAM7B"}
1
+ {"version":3,"file":"file-dao-state.repository.d.ts","sourceRoot":"","sources":["../../../src/adapters/persistence/file-dao-state.repository.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAsB,KAAK,QAAQ,EAAuB,MAAM,sBAAsB,CAAC;AAU9F;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAWpD;AAoDD,qFAAqF;AACrF,qBAAa,sBAAuB,YAAW,sBAAsB;IAWjE,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,UAAU,CAAoC;IAEtD,wFAAwF;IACxF,OAAO,CAAC,cAAc,CAAgB;IAEtC,6EAA6E;IAC7E,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO;IAyBP,wFAAwF;WAC1E,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,sBAAsB;WAS5E,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAqC/D,GAAG,IAAI,QAAQ;IAIT,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBrC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;;;;;;OAUG;YACW,6BAA6B;IA0C3C,2HAA2H;IAC3H,OAAO,CAAC,eAAe;YAiBT,gBAAgB;YAYhB,cAAc;CAM7B;AA0BD,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAsDvF"}
@@ -1,65 +1,244 @@
1
1
  import { promises as fs } from "node:fs";
2
2
  import path from "node:path";
3
+ import { logger } from "../../observability/logging.js";
3
4
  import { createInitialState } from "../../types/index.js";
4
5
  function formatJson(value) {
5
6
  return `${JSON.stringify(value, null, 2)}\n`;
6
7
  }
8
+ function isPositiveInteger(value) {
9
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
10
+ }
11
+ /**
12
+ * Repair ID counters from the maximum existing ids (issue #157). Shared by
13
+ * every load path (loadState and FileDaoStateRepository.open) so both produce
14
+ * identical, collision-free counters — e.g. a nextProposalId left behind a
15
+ * hand-edit or a restored backup no longer yields duplicate proposal ids.
16
+ */
17
+ export function repairCounters(state) {
18
+ const highestProposalId = state.proposals.reduce((max, proposal) => {
19
+ const id = proposal.id;
20
+ return isPositiveInteger(id) ? Math.max(max, id) : max;
21
+ }, 0);
22
+ if (state.nextProposalId <= highestProposalId)
23
+ state.nextProposalId = highestProposalId + 1;
24
+ const highestAuditId = state.auditLog.reduce((max, entry) => {
25
+ const id = entry?.id;
26
+ return isPositiveInteger(id) ? Math.max(max, id) : max;
27
+ }, 0);
28
+ if (state.nextAuditId <= highestAuditId)
29
+ state.nextAuditId = highestAuditId + 1;
30
+ }
31
+ function readRevision(value) {
32
+ return isPositiveInteger(value.stateRevision) ? value.stateRevision : 0;
33
+ }
7
34
  function repairState(value, daoRoot) {
8
35
  const fallback = createInitialState(daoRoot);
9
36
  const state = { ...fallback, ...value, daoRoot };
10
- state.proposals = Array.isArray(value.proposals) ? value.proposals : [];
11
- state.agents = Array.isArray(value.agents) ? value.agents : [];
12
- state.auditLog = Array.isArray(value.auditLog) ? value.auditLog : [];
13
- state.controlResults = value.controlResults && !Array.isArray(value.controlResults) ? value.controlResults : {};
14
- state.deliveryPlans = value.deliveryPlans && !Array.isArray(value.deliveryPlans) ? value.deliveryPlans : {};
15
- state.artefacts = value.artefacts && !Array.isArray(value.artefacts) ? value.artefacts : {};
16
- state.outcomes = value.outcomes && !Array.isArray(value.outcomes) ? value.outcomes : {};
17
- state.snapshots = value.snapshots && !Array.isArray(value.snapshots) ? value.snapshots : {};
18
- state.verifications = value.verifications && !Array.isArray(value.verifications) ? value.verifications : {};
19
- const nextProposalId = value.nextProposalId;
20
- const nextAuditId = value.nextAuditId;
21
- state.nextProposalId =
22
- typeof nextProposalId === "number" && Number.isInteger(nextProposalId) && nextProposalId > 0 ? nextProposalId : 1;
23
- state.nextAuditId =
24
- typeof nextAuditId === "number" && Number.isInteger(nextAuditId) && nextAuditId > 0 ? nextAuditId : 1;
25
- return state;
37
+ let repaired = false;
38
+ // Shape substitution means the file was damaged (partial write, manual edit,
39
+ // restore): keep defaults but flag it so the original gets backed up.
40
+ const arrayOr = (candidate, fallbackValue) => {
41
+ if (Array.isArray(candidate))
42
+ return candidate;
43
+ repaired = true;
44
+ return fallbackValue;
45
+ };
46
+ const recordOr = (candidate, fallbackValue) => {
47
+ // Plain objects only (review): a truthy primitive (string/number) in a
48
+ // corrupted state.json must be substituted, not adopted as a record.
49
+ if (typeof candidate === "object" && candidate !== null && !Array.isArray(candidate))
50
+ return candidate;
51
+ repaired = true;
52
+ return fallbackValue;
53
+ };
54
+ const intOr = (candidate, fallbackValue) => {
55
+ if (isPositiveInteger(candidate))
56
+ return candidate;
57
+ repaired = true;
58
+ return fallbackValue;
59
+ };
60
+ state.proposals = arrayOr(value.proposals, []);
61
+ state.agents = arrayOr(value.agents, []);
62
+ state.auditLog = arrayOr(value.auditLog, []);
63
+ state.controlResults = recordOr(value.controlResults, {});
64
+ state.deliveryPlans = recordOr(value.deliveryPlans, {});
65
+ state.artefacts = recordOr(value.artefacts, {});
66
+ state.outcomes = recordOr(value.outcomes, {});
67
+ state.snapshots = recordOr(value.snapshots, {});
68
+ state.verifications = recordOr(value.verifications, {});
69
+ state.nextProposalId = intOr(value.nextProposalId, 1);
70
+ state.nextAuditId = intOr(value.nextAuditId, 1);
71
+ state.stateRevision = readRevision(value);
72
+ repairCounters(state);
73
+ return { state, repaired };
26
74
  }
27
75
  /** Instance-owned filesystem adapter. No process-global DAO state or write cache. */
28
76
  export class FileDaoStateRepository {
29
77
  state;
30
78
  daoRoot;
31
79
  writeCache = new Map();
32
- constructor(state, daoRoot) {
80
+ writeQueue = Promise.resolve();
81
+ /** Last state.json content this instance read or wrote, for cheap divergence checks. */
82
+ rawStateOnDisk;
83
+ /** Revision this instance last read from, or wrote to, disk (issue #153). */
84
+ seenRevision;
85
+ constructor(state, daoRoot, rawStateOnDisk,
86
+ /** Revision already extracted by the caller's parse — passing it avoids a
87
+ * second full JSON.parse of state.json (measured +86% on a 500-proposal
88
+ * reload when this constructor re-parsed). */
89
+ seenRevision) {
33
90
  this.state = state;
34
91
  this.daoRoot = daoRoot;
92
+ this.rawStateOnDisk = rawStateOnDisk;
93
+ if (seenRevision !== undefined) {
94
+ this.seenRevision = seenRevision;
95
+ return;
96
+ }
97
+ let revision = 0;
98
+ if (rawStateOnDisk) {
99
+ try {
100
+ revision = readRevision(JSON.parse(rawStateOnDisk));
101
+ }
102
+ catch {
103
+ revision = 0;
104
+ }
105
+ }
106
+ this.seenRevision = revision;
107
+ }
108
+ /** Wrap already-loaded state so compatibility loaders share the locked persist path. */
109
+ static fromLoaded(state, rawStateOnDisk) {
110
+ return new FileDaoStateRepository(state, state.daoRoot, rawStateOnDisk, isPositiveInteger(state.stateRevision) ? state.stateRevision : undefined);
35
111
  }
36
112
  static async open(cwd) {
37
113
  const daoRoot = path.join(cwd, ".dao");
38
114
  await fs.mkdir(daoRoot, { recursive: true });
39
115
  const statePath = path.join(daoRoot, "state.json");
40
116
  let state = createInitialState(daoRoot);
117
+ let rawState = null;
41
118
  try {
42
- const parsed = JSON.parse(await fs.readFile(statePath, "utf8"));
43
- state = repairState(parsed, daoRoot);
119
+ rawState = await fs.readFile(statePath, "utf8");
44
120
  }
45
121
  catch (error) {
46
- if (error.code !== "ENOENT")
47
- throw error;
122
+ if (error.code !== "ENOENT") {
123
+ throw new Error(`Failed to read DAO state at ${statePath}: ${error instanceof Error ? error.message : String(error)}`);
124
+ }
125
+ }
126
+ if (rawState !== null) {
127
+ let parsed;
128
+ try {
129
+ parsed = JSON.parse(rawState);
130
+ }
131
+ catch (error) {
132
+ // Same wrapping as loadState: a raw SyntaxError names no file and the
133
+ // CLI/MCP (which load through open()) would give the user no hint.
134
+ throw new Error(`Corrupt DAO state at ${statePath}: ${error instanceof Error ? error.message : String(error)}`);
135
+ }
136
+ const repaired = repairState(parsed, daoRoot);
137
+ state = repaired.state;
138
+ if (repaired.repaired) {
139
+ // The damaged original is about to be silently overwritten by the
140
+ // first persist: preserve it for forensics (issue #167.6).
141
+ const backupPath = `${statePath}.backup-${new Date().toISOString().replace(/[:.]/g, "-")}`;
142
+ await fs.copyFile(statePath, backupPath).catch(() => undefined);
143
+ logger.warn(`⚠ state.json needed shape repair; original backed up to ${backupPath}`);
144
+ }
48
145
  }
49
- return new FileDaoStateRepository(state, daoRoot);
146
+ return new FileDaoStateRepository(state, daoRoot, rawState, state.stateRevision);
50
147
  }
51
148
  get() {
52
149
  return this.state;
53
150
  }
54
151
  async persist() {
55
- await fs.mkdir(this.daoRoot, { recursive: true });
56
- await this.writeIfChanged(path.join(this.daoRoot, "state.json"), this.state);
57
- await this.persistDecisions();
152
+ const task = async () => {
153
+ // No-op persist: nothing to write means no writer, so neither the
154
+ // inter-process lock nor the on-disk concurrency check is needed.
155
+ if (!this.hasPendingWrites())
156
+ return;
157
+ await fs.mkdir(this.daoRoot, { recursive: true });
158
+ await withFileLock(this.daoRoot, async () => {
159
+ const diskRevision = await this.checkNoConcurrentModification();
160
+ // Monotonic revision (issue #153): move past whatever is on disk so a
161
+ // stale copy of this instance can never be accepted again.
162
+ this.state.stateRevision = Math.max(diskRevision, this.seenRevision) + 1;
163
+ const statePath = path.join(this.daoRoot, "state.json");
164
+ await this.writeIfChanged(statePath, this.state);
165
+ this.rawStateOnDisk = this.writeCache.get(statePath) ?? null;
166
+ this.seenRevision = this.state.stateRevision;
167
+ await this.persistDecisions();
168
+ });
169
+ };
170
+ const queued = this.writeQueue.then(task, task);
171
+ this.writeQueue = queued.catch(() => { });
172
+ await queued;
58
173
  }
59
- async persistDecisions() {
60
- const decisionsDir = path.join(this.daoRoot, "decisions");
61
- await fs.mkdir(decisionsDir, { recursive: true });
62
- const decisions = this.state.proposals
174
+ /**
175
+ * Whether persist() would write anything. Mirrors the per-file decisions in
176
+ * writeIfChanged/persistDecisions: when every serialized payload matches the
177
+ * write cache, persist is a no-op and can skip lock, check and I/O.
178
+ */
179
+ hasPendingWrites() {
180
+ if (this.writeCache.get(path.join(this.daoRoot, "state.json")) !== formatJson(this.state))
181
+ return true;
182
+ const decisions = this.closedDecisions();
183
+ if (this.writeCache.get(path.join(this.daoRoot, "decisions", "index.json")) !== formatJson(decisions)) {
184
+ return true;
185
+ }
186
+ return decisions.some((decision) => this.writeCache.get(path.join(this.daoRoot, "decisions", `${decision.id.toString().padStart(3, "0")}.json`)) !==
187
+ formatJson(decision));
188
+ }
189
+ /**
190
+ * Fail-fast optimistic concurrency: if another process persisted a state
191
+ * this instance has not seen, refuse to overwrite it instead of silently
192
+ * dropping votes/proposals (last-writer-wins).
193
+ *
194
+ * Returns the revision currently on disk. Two layers:
195
+ * 1. stateRevision comparison (issue #153) — catches ANY divergence,
196
+ * including votes added to a proposal known to both processes.
197
+ * 2. proposal-id/counter checks — catch hand-edited files whose revision
198
+ * was not bumped (state.json is a documented, readable format).
199
+ */
200
+ async checkNoConcurrentModification() {
201
+ let raw;
202
+ try {
203
+ raw = await fs.readFile(path.join(this.daoRoot, "state.json"), "utf8");
204
+ }
205
+ catch (error) {
206
+ if (error.code === "ENOENT")
207
+ return 0;
208
+ throw error;
209
+ }
210
+ // Byte-identical to what this instance last read or wrote: no other
211
+ // writer touched the file. Avoids a full JSON.parse of a potentially
212
+ // large state on every persist.
213
+ if (raw === this.rawStateOnDisk)
214
+ return this.seenRevision;
215
+ const onDisk = JSON.parse(raw);
216
+ const diskRevision = readRevision(onDisk);
217
+ if (diskRevision !== this.seenRevision) {
218
+ throw new Error(`Concurrent modification detected in ${path.join(this.daoRoot, "state.json")}: ` +
219
+ `disk revision (${diskRevision}) differs from the revision this instance last saw (${this.seenRevision}). ` +
220
+ "Reopen the repository and retry.");
221
+ }
222
+ if (!onDisk || !Array.isArray(onDisk.proposals))
223
+ return diskRevision;
224
+ const diskIds = new Set(onDisk.proposals.map((p) => p.id));
225
+ const memIds = new Set(this.state.proposals.map((p) => p.id));
226
+ for (const id of diskIds) {
227
+ if (!memIds.has(id)) {
228
+ throw new Error(`Concurrent modification detected in ${path.join(this.daoRoot, "state.json")}: ` +
229
+ `proposal #${String(id)} exists on disk but not in memory. Reopen the repository and retry.`);
230
+ }
231
+ }
232
+ const diskNext = typeof onDisk.nextProposalId === "number" ? onDisk.nextProposalId : 1;
233
+ if (diskNext > this.state.nextProposalId) {
234
+ throw new Error(`Concurrent modification detected in ${path.join(this.daoRoot, "state.json")}: ` +
235
+ `disk nextProposalId (${diskNext}) is ahead of memory (${this.state.nextProposalId}). Reopen and retry.`);
236
+ }
237
+ return diskRevision;
238
+ }
239
+ /** Decisions to persist: closed proposals only, ordered by id. Single source for persistDecisions and hasPendingWrites. */
240
+ closedDecisions() {
241
+ return this.state.proposals
63
242
  .filter((proposal) => proposal.status !== "open" && proposal.status !== "deliberating")
64
243
  .map((proposal) => ({
65
244
  id: proposal.id,
@@ -71,6 +250,11 @@ export class FileDaoStateRepository {
71
250
  resolvedAt: proposal.resolvedAt,
72
251
  }))
73
252
  .sort((left, right) => left.id - right.id);
253
+ }
254
+ async persistDecisions() {
255
+ const decisionsDir = path.join(this.daoRoot, "decisions");
256
+ await fs.mkdir(decisionsDir, { recursive: true });
257
+ const decisions = this.closedDecisions();
74
258
  await this.writeIfChanged(path.join(decisionsDir, "index.json"), decisions);
75
259
  await Promise.all(decisions.map((decision) => this.writeIfChanged(path.join(decisionsDir, `${decision.id.toString().padStart(3, "0")}.json`), decision)));
76
260
  }
@@ -78,8 +262,110 @@ export class FileDaoStateRepository {
78
262
  const serialized = formatJson(value);
79
263
  if (this.writeCache.get(filePath) === serialized)
80
264
  return;
81
- await fs.writeFile(filePath, serialized, "utf8");
265
+ await writeAtomic(filePath, serialized);
82
266
  this.writeCache.set(filePath, serialized);
83
267
  }
84
268
  }
269
+ async function writeAtomic(filePath, content) {
270
+ const tmpPath = `${filePath}.tmp-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
271
+ try {
272
+ await fs.writeFile(tmpPath, content, "utf8");
273
+ await fs.rename(tmpPath, filePath);
274
+ }
275
+ catch (error) {
276
+ await safeUnlink(tmpPath);
277
+ throw error;
278
+ }
279
+ }
280
+ async function safeUnlink(p) {
281
+ try {
282
+ await fs.unlink(p);
283
+ }
284
+ catch {
285
+ // Ignore — file may not exist or may already be gone.
286
+ }
287
+ }
288
+ const LOCK_FILE = "state.lock";
289
+ const LOCK_TIMEOUT_MS = 5000;
290
+ const LOCK_RETRY_MS = 25;
291
+ const LOCK_STALE_MS = 10000;
292
+ export async function withFileLock(daoRoot, fn) {
293
+ const lockPath = path.join(daoRoot, LOCK_FILE);
294
+ // Callers are responsible for creating daoRoot before locking.
295
+ const deadline = Date.now() + LOCK_TIMEOUT_MS;
296
+ // Unique token (issue #167.1): the release step only removes the lock file
297
+ // when it still holds ITS OWN token, so a stale takeover can never trick a
298
+ // live writer into deleting someone else's lock.
299
+ const token = `${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
300
+ const lockPayload = () => JSON.stringify({ pid: process.pid, ts: Date.now(), token });
301
+ for (;;) {
302
+ try {
303
+ await fs.writeFile(lockPath, lockPayload(), { flag: "wx" });
304
+ break;
305
+ }
306
+ catch (error) {
307
+ if (error.code !== "EEXIST")
308
+ throw error;
309
+ if (await isLockStale(lockPath)) {
310
+ await safeUnlink(lockPath);
311
+ continue;
312
+ }
313
+ if (Date.now() >= deadline) {
314
+ throw new Error(`Timed out acquiring DAO lock at ${lockPath} (another writer holds it)`);
315
+ }
316
+ await new Promise((r) => setTimeout(r, LOCK_RETRY_MS));
317
+ }
318
+ }
319
+ // Heartbeat: refresh the timestamp while the critical section runs, so a
320
+ // legitimately long write is not declared stale by a waiting process. Only
321
+ // refresh while the lock file still holds OUR token (review): after a
322
+ // stale takeover by another writer, the old owner's heartbeat must not
323
+ // clobber the new owner's token.
324
+ const heartbeat = setInterval(() => {
325
+ void (async () => {
326
+ try {
327
+ const raw = await fs.readFile(lockPath, "utf8");
328
+ const parsed = JSON.parse(raw);
329
+ if (parsed.token !== token)
330
+ return; // we no longer own the lock file
331
+ await fs.writeFile(lockPath, lockPayload(), { flag: "w" });
332
+ }
333
+ catch {
334
+ // Lock already gone or unreadable — nothing to refresh.
335
+ }
336
+ })();
337
+ }, LOCK_STALE_MS / 2);
338
+ try {
339
+ return await fn();
340
+ }
341
+ finally {
342
+ clearInterval(heartbeat);
343
+ try {
344
+ const raw = await fs.readFile(lockPath, "utf8");
345
+ const parsed = JSON.parse(raw);
346
+ if (parsed.token === token)
347
+ await safeUnlink(lockPath);
348
+ }
349
+ catch {
350
+ // Lock already gone or unreadable — nothing to remove.
351
+ }
352
+ }
353
+ }
354
+ async function isLockStale(lockPath) {
355
+ try {
356
+ const raw = await fs.readFile(lockPath, "utf8");
357
+ const parsed = JSON.parse(raw);
358
+ return typeof parsed.ts === "number" && Date.now() - parsed.ts > LOCK_STALE_MS;
359
+ }
360
+ catch {
361
+ // Unreadable lock: treat missing as not-stale (retry), corrupt as stale.
362
+ try {
363
+ await fs.stat(lockPath);
364
+ }
365
+ catch {
366
+ return false;
367
+ }
368
+ return true;
369
+ }
370
+ }
85
371
  //# sourceMappingURL=file-dao-state.repository.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-dao-state.repository.js","sourceRoot":"","sources":["../../../src/adapters/persistence/file-dao-state.repository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-dao-state.repository.js","sourceRoot":"","sources":["../../../src/adapters/persistence/file-dao-state.repository.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fs-ship-audit.store.d.ts","sourceRoot":"","sources":["../../../src/adapters/ship-audit/fs-ship-audit.store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIvF,qBAAa,gBAAiB,YAAW,kBAAkB;;gBAGtC,cAAc,EAAE,MAAM;IAI5B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAgB3D,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CA0BrG"}
1
+ {"version":3,"file":"fs-ship-audit.store.d.ts","sourceRoot":"","sources":["../../../src/adapters/ship-audit/fs-ship-audit.store.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIvF,qBAAa,gBAAiB,YAAW,kBAAkB;;gBAGtC,cAAc,EAAE,MAAM;IAI5B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAgB3D,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhD,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;CAwErG"}
@@ -4,8 +4,10 @@
4
4
  // Persists audit-challenge snapshots under <repositoryRoot>/.dao/ship-audits/
5
5
  // as <proposalId>.json. Read-soft: a missing or unreadable file yields null
6
6
  // (a fresh cycle), never an error — the challenge must still gate.
7
+ var _a;
7
8
  import { promises as fs } from "node:fs";
8
9
  import { join, resolve, sep } from "node:path";
10
+ import { writeAtomic } from "../../persistence.js";
9
11
  const SAFE_ID = /^\d+$/;
10
12
  export class FsShipAuditStore {
11
13
  #directory;
@@ -35,15 +37,16 @@ export class FsShipAuditStore {
35
37
  async save(snapshot) {
36
38
  const file = this.#fileFor(snapshot.proposalId);
37
39
  await fs.mkdir(this.#directory, { recursive: true });
38
- await fs.writeFile(file, `${JSON.stringify(snapshot, null, 2)}\n`, "utf8");
40
+ await writeAtomic(file, `${JSON.stringify(snapshot, null, 2)}\n`);
39
41
  }
40
42
  async claim(proposalId) {
41
43
  const lock = this.#fileFor(proposalId).replace(/\.json$/, ".lock");
42
44
  await fs.mkdir(this.#directory, { recursive: true });
43
45
  try {
44
46
  // O_EXCL ('wx'): exactly one concurrent caller across processes wins.
47
+ const payload = `${JSON.stringify({ pid: process.pid, ts: Date.now() })}\n`;
45
48
  const handle = await fs.open(lock, "wx");
46
- await handle.write(`${process.pid}\n`);
49
+ await handle.write(payload);
47
50
  await handle.close();
48
51
  return {
49
52
  acquired: true,
@@ -53,9 +56,60 @@ export class FsShipAuditStore {
53
56
  };
54
57
  }
55
58
  catch {
59
+ // EEXIST: a claim already exists. If its writer is provably gone
60
+ // (dead pid) or it is old enough, reclaim it instead of failing ships
61
+ // forever until manual cleanup (issue #167.5).
62
+ if (await this.#claimIsAbandoned(lock)) {
63
+ await fs.rm(lock, { force: true }).catch(() => undefined);
64
+ return this.claim(proposalId);
65
+ }
56
66
  return { acquired: false, release: async () => undefined };
57
67
  }
58
68
  }
69
+ /** A claim is abandoned when the owning pid no longer exists, or when it
70
+ * is older than the staleness window (crash without cleanup, cross-machine
71
+ * writers where the pid check cannot apply). */
72
+ static #CLAIM_STALE_MS = 30 * 60 * 1000;
73
+ async #claimIsAbandoned(lock) {
74
+ try {
75
+ const raw = await fs.readFile(lock, "utf8");
76
+ let pid;
77
+ let ts;
78
+ try {
79
+ const parsed = JSON.parse(raw);
80
+ if (typeof parsed.pid === "number")
81
+ pid = parsed.pid;
82
+ if (typeof parsed.ts === "number")
83
+ ts = parsed.ts;
84
+ }
85
+ catch {
86
+ // Legacy format: a bare pid line.
87
+ const parsedPid = Number.parseInt(raw.trim(), 10);
88
+ if (Number.isInteger(parsedPid))
89
+ pid = parsedPid;
90
+ }
91
+ if (pid !== undefined && Number.isInteger(pid) && pid > 0) {
92
+ try {
93
+ process.kill(pid, 0); // liveness probe — throws if the process is gone
94
+ // Alive: only age can make the claim abandonable.
95
+ }
96
+ catch (error) {
97
+ // POSIX (review): EPERM means the process EXISTS but is owned by
98
+ // another user — reclaiming on EPERM would break mutual exclusion.
99
+ // Only ESRCH ("no such process") proves the owner is gone.
100
+ if (error.code === "ESRCH")
101
+ return true;
102
+ // Any other probe error: fall through to the age check.
103
+ }
104
+ }
105
+ if (ts !== undefined && Date.now() - ts > _a.#CLAIM_STALE_MS)
106
+ return true;
107
+ return false;
108
+ }
109
+ catch {
110
+ return false; // unreadable claim: keep failing closed
111
+ }
112
+ }
59
113
  #fileFor(proposalId) {
60
114
  const name = String(proposalId);
61
115
  if (!SAFE_ID.test(name))
@@ -66,4 +120,5 @@ export class FsShipAuditStore {
66
120
  return file;
67
121
  }
68
122
  }
123
+ _a = FsShipAuditStore;
69
124
  //# sourceMappingURL=fs-ship-audit.store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fs-ship-audit.store.js","sourceRoot":"","sources":["../../../src/adapters/ship-audit/fs-ship-audit.store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fs-ship-audit.store.js","sourceRoot":"","sources":["../../../src/adapters/ship-audit/fs-ship-audit.store.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import type { ClockPort } from "../../ports/clock.js";
2
2
  import type { DaoStateRepositoryPort } from "../../ports/repository.js";
3
- import type { ControlCheckResult } from "../../types/index.js";
3
+ import type { ControlCheckResult, Proposal } from "../../types/index.js";
4
4
  export type ControlProposalResult = {
5
5
  ok: true;
6
6
  control: ControlCheckResult;
7
+ status: Proposal["status"];
7
8
  } | {
8
9
  ok: false;
9
10
  error: string;
@@ -1 +1 @@
1
- {"version":3,"file":"control-proposal.use-case.d.ts","sourceRoot":"","sources":["../../../src/application/proposals/control-proposal.use-case.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAc,kBAAkB,EAAY,MAAM,sBAAsB,CAAC;AAErF,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7G,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,EAAE;QAC7B,UAAU,EAAE,sBAAsB,CAAC;QACnC,KAAK,EAAE,SAAS,CAAC;KAClB;IAGU,OAAO,CAAC,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAiDlH,OAAO,CAAC,KAAK;CAYd"}
1
+ {"version":3,"file":"control-proposal.use-case.d.ts","sourceRoot":"","sources":["../../../src/application/proposals/control-proposal.use-case.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAc,kBAAkB,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE/F,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA;CAAE,GACrE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,EAAE;QAC7B,UAAU,EAAE,sBAAsB,CAAC;QACnC,KAAK,EAAE,SAAS,CAAC;KAClB;IAGU,OAAO,CAAC,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA8DlH,OAAO,CAAC,KAAK;CAYd"}