@lmzhen/dsh-evolution-state-json 0.3.74 → 0.3.77
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.
- package/README.md +2 -0
- package/lib/index.js +34 -9
- package/package.json +7 -13
- package/lib/invariant.js +0 -8
- package/lib/types/invariant.d.ts +0 -5
package/README.md
CHANGED
|
@@ -26,3 +26,5 @@ Independent of request-prefix construction. This package does not alter the asse
|
|
|
26
26
|
- V25-11 (v25): the review-state table is likewise BOUNDED — `REVIEW_STATE_SESSION_CAP` (500, seam constant) rows keyed by session; on every save the least-recently-active sessions (provider-stamped `updatedAt`, stored on disk only) are pruned. The stamp is stripped on read, so the consumer-facing record shape is unchanged.
|
|
27
27
|
- JSON provider serializes writers inside one process AND through the IO backend's cross-process transact lock (an internal transact wrapper — not public API, audit v10 S-03 — wraps every mutation, 0.3.20/0.3.27) — this provider is NOT limited to single-process safety. The caveat below is about the DSH storage-domain providers (`storage-json` documents no cross-process write locking) when the DOMAIN provider is used instead; multi-process deployments should route the evolution domain to a backend with cross-process semantics such as SQLite or remote storage.
|
|
28
28
|
|
|
29
|
+
**Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
|
|
30
|
+
|
package/lib/index.js
CHANGED
|
@@ -268,11 +268,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
268
268
|
for (const entry of rawBak) if (entry && typeof entry.id === "string") ids.add(entry.id);
|
|
269
269
|
}
|
|
270
270
|
} catch (bakError) {
|
|
271
|
-
if (bakError?.name === QUARANTINE_ERROR_NAME) throw bakError;
|
|
272
271
|
ctx.logger.warn(`evolution-state-json: pending archive .bak unreadable (${bakError instanceof Error ? bakError.message : String(bakError)}) — archived ids that live only in the .bak do not exclude their legacy twins until the sidecar is readable again`);
|
|
273
272
|
}
|
|
274
273
|
} catch (error) {
|
|
275
|
-
if (error?.name === QUARANTINE_ERROR_NAME) throw error;
|
|
276
274
|
ctx.logger.warn(`evolution-state-json: pending archive sidecars unreadable (${error instanceof Error ? error.message : String(error)}) — the V5-02 legacy ghost-twin filter runs WITHOUT the archived-id exclusion until the archive is readable again`);
|
|
277
275
|
}
|
|
278
276
|
return ids;
|
|
@@ -287,14 +285,38 @@ function apply(ctx, rawConfig = {}) {
|
|
|
287
285
|
}
|
|
288
286
|
return retired;
|
|
289
287
|
}
|
|
288
|
+
let pendingKeyWarned = false;
|
|
289
|
+
function keyPendingById(map) {
|
|
290
|
+
const keyed = {};
|
|
291
|
+
if (map === null) return keyed;
|
|
292
|
+
let drifted = 0;
|
|
293
|
+
let dropped = 0;
|
|
294
|
+
for (const [key, record] of Object.entries(map)) {
|
|
295
|
+
const id = typeof record.id === "string" ? record.id : key;
|
|
296
|
+
if (key !== id) {
|
|
297
|
+
if (keyed[id] !== void 0) {
|
|
298
|
+
dropped += 1;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
drifted += 1;
|
|
302
|
+
}
|
|
303
|
+
keyed[id] = record;
|
|
304
|
+
}
|
|
305
|
+
if ((drifted > 0 || dropped > 0) && !pendingKeyWarned) {
|
|
306
|
+
pendingKeyWarned = true;
|
|
307
|
+
ctx.logger.warn(`evolution-state-json: ${drifted} pending table entr(ies) were keyed by something other than record.id (${dropped} same-id residue row(s) dropped) — re-keyed by id, so a drifted row is reachable by claim/resolve again`);
|
|
308
|
+
}
|
|
309
|
+
return keyed;
|
|
310
|
+
}
|
|
290
311
|
async function retireLegacyOnce(legacy) {
|
|
291
312
|
if (legacyMigrated) return {};
|
|
313
|
+
const keyedLegacy = keyPendingById(legacy);
|
|
292
314
|
try {
|
|
293
315
|
const retired = {};
|
|
294
316
|
await jsonTransact(ctx, io, root, PENDING_STATE_FILE, async (fresh) => {
|
|
295
|
-
const merged =
|
|
317
|
+
const merged = keyPendingById(fresh);
|
|
296
318
|
const archivedIds = await readArchivedIds();
|
|
297
|
-
for (const [id, record] of Object.entries(
|
|
319
|
+
for (const [id, record] of Object.entries(keyedLegacy)) {
|
|
298
320
|
if (id in merged) continue;
|
|
299
321
|
if (archivedIds.has(id)) continue;
|
|
300
322
|
if (gateDroppedCurrent.has(id)) continue;
|
|
@@ -314,11 +336,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
314
336
|
}
|
|
315
337
|
async function loadPendingMap() {
|
|
316
338
|
const [current, legacy] = await Promise.all([readJson(PENDING_STATE_FILE), readJson(PENDING_LEGACY_FILE)]);
|
|
339
|
+
const keyed = keyPendingById(current);
|
|
317
340
|
if (legacy !== null) return {
|
|
318
341
|
...await retireLegacyOnce(legacy),
|
|
319
|
-
...
|
|
342
|
+
...keyed
|
|
320
343
|
};
|
|
321
|
-
return { ...
|
|
344
|
+
return { ...keyed };
|
|
322
345
|
}
|
|
323
346
|
/** V6-01 (0.3.34): single-sourced legacy merge for the four mutation paths —
|
|
324
347
|
* the SAME exclusion as the retirement read path, so a mutation that runs
|
|
@@ -326,10 +349,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
326
349
|
* (the archive id set is read fresh on every merge — V11-B2; current-wins
|
|
327
350
|
* covers stale misses). */
|
|
328
351
|
async function mergedWithFilteredLegacy(legacy, current) {
|
|
329
|
-
|
|
352
|
+
const keyed = keyPendingById(current);
|
|
353
|
+
if (legacy === null) return keyed;
|
|
354
|
+
const archivedIds = await readArchivedIds();
|
|
330
355
|
return {
|
|
331
|
-
...filterLegacy(legacy,
|
|
332
|
-
...
|
|
356
|
+
...filterLegacy(keyPendingById(legacy), keyed, archivedIds),
|
|
357
|
+
...keyed
|
|
333
358
|
};
|
|
334
359
|
}
|
|
335
360
|
/** 0.3.22 (F-336): when the live pending map holds more than
|
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.
|
|
4
|
+
"version": "0.3.77",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"types": "./lib/types/index.d.ts",
|
|
19
19
|
"default": "./lib/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./invariant": {
|
|
22
|
-
"types": "./lib/types/invariant.d.ts",
|
|
23
|
-
"default": "./lib/invariant.js"
|
|
24
|
-
},
|
|
25
21
|
"./package.json": "./package.json"
|
|
26
22
|
},
|
|
27
23
|
"files": [
|
|
@@ -31,18 +27,16 @@
|
|
|
31
27
|
"license": "MIT",
|
|
32
28
|
"dependencies": {
|
|
33
29
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
34
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.3.77"
|
|
35
31
|
},
|
|
36
32
|
"peerDependencies": {
|
|
37
|
-
"@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
|
|
38
33
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
39
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
40
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
34
|
+
"@lmzhen/dsh-evolution-io": "^0.3.77",
|
|
35
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.77"
|
|
41
36
|
},
|
|
42
37
|
"devDependencies": {
|
|
43
|
-
"@
|
|
44
|
-
"@lmzhen/dsh-evolution-
|
|
45
|
-
"@lmzhen/dsh-evolution-
|
|
46
|
-
"@lmzhen/dsh-evolution-io-node": "^0.3.74"
|
|
38
|
+
"@lmzhen/dsh-evolution-io": "^0.3.77",
|
|
39
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.77",
|
|
40
|
+
"@lmzhen/dsh-evolution-io-node": "^0.3.77"
|
|
47
41
|
}
|
|
48
42
|
}
|
package/lib/invariant.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
//#region lib/types/invariant.js
|
|
2
|
-
const PACKAGE_NAME = "@lmzhen/dsh-evolution-state-json";
|
|
3
|
-
const name = "evolution-state-json-invariant";
|
|
4
|
-
const inject = ["invariants"];
|
|
5
|
-
const install = () => {};
|
|
6
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
7
|
-
//#endregion
|
|
8
|
-
export { apply, inject, name };
|
package/lib/types/invariant.d.ts
DELETED