@lmzhen/dsh-evolution-state-json 0.3.33 → 0.3.34

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 (2) hide show
  1. package/lib/index.js +40 -29
  2. package/package.json +6 -6
package/lib/index.js CHANGED
@@ -95,25 +95,35 @@ function apply(ctx, rawConfig) {
95
95
  }
96
96
  const mutate = makeSerialQueue();
97
97
  let legacyMigrated = false;
98
+ let archivedIdsCache = null;
99
+ async function readArchivedIds() {
100
+ if (archivedIdsCache !== null) return archivedIdsCache;
101
+ const ids = /* @__PURE__ */ new Set();
102
+ try {
103
+ const rawArchive = await readJson("pending-state-archive.json");
104
+ if (Array.isArray(rawArchive)) {
105
+ for (const entry of rawArchive) if (entry && typeof entry.id === "string") ids.add(entry.id);
106
+ }
107
+ } catch {}
108
+ archivedIdsCache = ids;
109
+ return ids;
110
+ }
111
+ function filterLegacy(legacy, current, archivedIds) {
112
+ const retired = {};
113
+ for (const [id, record] of Object.entries(legacy)) {
114
+ if (id in (current ?? {})) continue;
115
+ if (archivedIds.has(id)) continue;
116
+ retired[id] = record;
117
+ }
118
+ return retired;
119
+ }
98
120
  async function retireLegacyOnce(legacy, current) {
99
121
  if (legacyMigrated) return {};
100
122
  try {
101
- const archivedIds = /* @__PURE__ */ new Set();
102
- try {
103
- const rawArchive = await readJson("pending-state-archive.json");
104
- if (Array.isArray(rawArchive)) {
105
- for (const entry of rawArchive) if (entry && typeof entry.id === "string") archivedIds.add(entry.id);
106
- }
107
- } catch {}
108
- const retired = {};
109
- for (const [id, record] of Object.entries(legacy)) {
110
- if (id in (current ?? {})) continue;
111
- if (archivedIds.has(id)) continue;
112
- retired[id] = record;
113
- }
114
- await jsonTransact(io, root, "pending-state.json", () => ({
123
+ const retired = filterLegacy(legacy, current, await readArchivedIds());
124
+ await jsonTransact(io, root, "pending-state.json", (fresh) => ({
115
125
  ...retired,
116
- ...current ?? {}
126
+ ...fresh ?? {}
117
127
  }));
118
128
  await io().rename(pathOf("pending.json"), pathOf("pending.json.migrated"));
119
129
  legacyMigrated = true;
@@ -130,6 +140,17 @@ function apply(ctx, rawConfig) {
130
140
  };
131
141
  return { ...current ?? {} };
132
142
  }
143
+ /** V6-01 (0.3.34): single-sourced legacy merge for the four mutation paths —
144
+ * the SAME exclusion as the retirement read path, so a mutation that runs
145
+ * before any retirement cannot fixate a ghost pending twin in current
146
+ * (the archive id set is cached once; current-wins covers stale misses). */
147
+ async function mergedWithFilteredLegacy(legacy, current) {
148
+ if (legacy === null) return current;
149
+ return {
150
+ ...filterLegacy(legacy, current, await readArchivedIds()),
151
+ ...current
152
+ };
153
+ }
133
154
  /** 0.3.22 (F-336): when the live pending map holds more than
134
155
  * `PENDING_RESOLVED_CAP` resolved records, drop the oldest (by resolvedAt,
135
156
  * then insertion order on ties) from the map and return them for archiving.
@@ -244,8 +265,7 @@ function apply(ctx, rawConfig) {
244
265
  await mutate(async () => {
245
266
  await jsonTransact(io, root, "pending-state.json", async (current) => {
246
267
  return {
247
- ...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
248
- ...current ?? {},
268
+ ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}),
249
269
  [record.id]: record
250
270
  };
251
271
  });
@@ -255,10 +275,7 @@ function apply(ctx, rawConfig) {
255
275
  return await mutate(async () => {
256
276
  const slot = { claimed: null };
257
277
  await jsonTransact(io, root, "pending-state.json", async (current) => {
258
- const map = {
259
- ...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
260
- ...current ?? {}
261
- };
278
+ const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
262
279
  const record = map[id] ?? null;
263
280
  if (record === null || !canClaimPending(record.status)) return map;
264
281
  const now = Date.now();
@@ -277,10 +294,7 @@ function apply(ctx, rawConfig) {
277
294
  async releasePendingClaim(id, claimId) {
278
295
  await mutate(async () => {
279
296
  await jsonTransact(io, root, "pending-state.json", async (current) => {
280
- const map = {
281
- ...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
282
- ...current ?? {}
283
- };
297
+ const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
284
298
  const record = map[id];
285
299
  if (!record || record.claimedBy !== claimId) return map;
286
300
  record.status = releasedStatus(record.status);
@@ -298,10 +312,7 @@ function apply(ctx, rawConfig) {
298
312
  };
299
313
  let evicted = [];
300
314
  await jsonTransact(io, root, "pending-state.json", async (current) => {
301
- const map = {
302
- ...(legacyMigrated ? null : await readJson("pending.json")) ?? {},
303
- ...current ?? {}
304
- };
315
+ const map = { ...await mergedWithFilteredLegacy(legacyMigrated ? null : await readJson("pending.json"), current ?? {}) };
305
316
  const record = map[id] ?? null;
306
317
  if (record === null || !canResolvePending(record.status)) {
307
318
  result = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-state-json",
3
3
  "description": "JSON-file evolution state provider over the IO seam (community build)",
4
- "version": "0.3.33",
4
+ "version": "0.3.34",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,17 +31,17 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-core": "^0.3.33"
34
+ "@lmzhen/dsh-evolution-core": "^0.3.34"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
38
38
  "@deepseek-ai/cordis": "^4.0.1",
39
- "@lmzhen/dsh-evolution-io": "^0.3.33",
40
- "@lmzhen/dsh-evolution-state-storage": "^0.3.33"
39
+ "@lmzhen/dsh-evolution-io": "^0.3.34",
40
+ "@lmzhen/dsh-evolution-state-storage": "^0.3.34"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
- "@lmzhen/dsh-evolution-io": "^0.3.33",
45
- "@lmzhen/dsh-evolution-state-storage": "^0.3.33"
44
+ "@lmzhen/dsh-evolution-io": "^0.3.34",
45
+ "@lmzhen/dsh-evolution-state-storage": "^0.3.34"
46
46
  }
47
47
  }