@lmzhen/dsh-evolution-state-domain 0.3.62 → 0.3.64

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 (3) hide show
  1. package/README.md +1 -0
  2. package/lib/index.js +43 -11
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -23,4 +23,5 @@ Independent of request-prefix construction. This package does not alter the asse
23
23
 
24
24
 
25
25
  - Requires the host-plane `storage-domain` facility. The bundle row stays dormant when it is absent.
26
+ - P2-4 (v15): the live pending table is BOUNDED — resolved (approved/rejected) records are kept to the most recent `PENDING_RESOLVED_CAP` (200, seam constant in `evolution-state-storage`); the oldest by `resolvedAt` are deleted on resolve. The audit ARCHIVE sidecar that the json provider maintains beyond the cap is json-specific (the domain seam has no sidecar facility) — resolved records past the cap are gone, not archived.
26
27
 
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { DomainError, defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
3
- import { CURATOR_STATE_KEY, CURATOR_STATE_TABLE, PENDING_TABLE, PROVIDER_DOMAIN, REVIEW_STATE_TABLE, canClaimPending, canResolvePending, releasedStatus } from "@lmzhen/dsh-evolution-state-storage";
3
+ import { CURATOR_STATE_KEY, CURATOR_STATE_TABLE, PENDING_RESOLVED_CAP, PENDING_TABLE, PROVIDER_DOMAIN, REVIEW_STATE_TABLE, canClaimPending, canResolvePending, releasedStatus } from "@lmzhen/dsh-evolution-state-storage";
4
4
  //#region lib/types/index.js
5
5
  /**
6
6
  * storage-domain provider for evolution state.
@@ -116,16 +116,22 @@ function apply(ctx) {
116
116
  const provider = {
117
117
  name: PROVIDER_DOMAIN,
118
118
  async loadReviewState(sessionId) {
119
- return (await ensure()).table(REVIEW_STATE_TABLE).get(sessionId) ?? null;
119
+ const record = (await ensure()).table(REVIEW_STATE_TABLE).get(sessionId);
120
+ return record === void 0 ? null : structuredClone(record);
120
121
  },
121
122
  async saveReviewState(sessionId, record) {
122
- await (await ensure()).table(REVIEW_STATE_TABLE).put(sessionId, record);
123
+ const parsed = reviewStateSchema.safeParse(record);
124
+ if (!parsed.success) throw new Error(`evolution-state-domain: refusing to persist an invalid review-state record: ${parsed.error.issues[0]?.message ?? "schema mismatch"}`);
125
+ await (await ensure()).table(REVIEW_STATE_TABLE).put(sessionId, parsed.data);
123
126
  },
124
127
  async loadCuratorState() {
125
- return (await ensure()).table(CURATOR_STATE_TABLE).get(CURATOR_STATE_KEY) ?? null;
128
+ const record = (await ensure()).table(CURATOR_STATE_TABLE).get(CURATOR_STATE_KEY);
129
+ return record === void 0 ? null : structuredClone(record);
126
130
  },
127
131
  async saveCuratorState(record) {
128
- await (await ensure()).table(CURATOR_STATE_TABLE).put(CURATOR_STATE_KEY, record);
132
+ const parsed = curatorStateSchema.safeParse(record);
133
+ if (!parsed.success) throw new Error(`evolution-state-domain: refusing to persist an invalid curator-state record: ${parsed.error.issues[0]?.message ?? "schema mismatch"}`);
134
+ await (await ensure()).table(CURATOR_STATE_TABLE).put(CURATOR_STATE_KEY, parsed.data);
129
135
  },
130
136
  async transactCuratorState(task) {
131
137
  const table = (await ensure()).table(CURATOR_STATE_TABLE);
@@ -146,10 +152,16 @@ function apply(ctx) {
146
152
  else await table.delete(CURATOR_STATE_KEY);
147
153
  },
148
154
  async listPending(status = "pending") {
149
- return [...(await ensure()).table(PENDING_TABLE).entries()].map(([, value]) => value).filter((record) => record.status === status);
155
+ return [...(await ensure()).table(PENDING_TABLE).entries()].map(([, value]) => structuredClone(value)).filter((record) => record.status === status);
150
156
  },
151
157
  async savePending(record) {
152
- await (await ensure()).table(PENDING_TABLE).put(record.id, record);
158
+ if (!Object.prototype.hasOwnProperty.call(record, "args")) throw new Error("evolution-state-domain: refusing to persist a pending record without the required \"args\" key");
159
+ const parsed = pendingSchema.safeParse({
160
+ ...record,
161
+ args: record.args
162
+ });
163
+ if (!parsed.success) throw new Error(`evolution-state-domain: refusing to persist an invalid pending record: ${parsed.error.issues[0]?.message ?? "schema mismatch"}`);
164
+ await (await ensure()).table(PENDING_TABLE).put(record.id, parsed.data);
153
165
  },
154
166
  async claimPending(id, claimId) {
155
167
  const table = (await ensure()).table(PENDING_TABLE);
@@ -166,7 +178,7 @@ function apply(ctx) {
166
178
  };
167
179
  return slot.record;
168
180
  });
169
- return slot.record === null ? null : { ...slot.record };
181
+ return slot.record === null ? null : structuredClone(slot.record);
170
182
  } catch (error) {
171
183
  if (error instanceof DomainError && error.code === "missing-key") return null;
172
184
  throw error;
@@ -195,7 +207,7 @@ function apply(ctx) {
195
207
  const table = (await ensure()).table(PENDING_TABLE);
196
208
  try {
197
209
  const resolved = { record: null };
198
- const rawRecord = await table.update(id, (current) => {
210
+ const record = await table.update(id, (current) => {
199
211
  if (!canResolvePending(current.status)) return current;
200
212
  if (expectedClaimId !== void 0 && current.claimedBy !== expectedClaimId) return current;
201
213
  resolved.record = {
@@ -205,12 +217,32 @@ function apply(ctx) {
205
217
  };
206
218
  return resolved.record;
207
219
  });
220
+ if (resolved.record !== null) {
221
+ const resolvedEntries = [...table.entries()].map(([key, record]) => ({
222
+ key,
223
+ record
224
+ })).filter((entry) => entry.record.status === "approved" || entry.record.status === "rejected");
225
+ const resolvedAtMs = (record) => {
226
+ const parsed = Date.parse(record.resolvedAt ?? "");
227
+ return Number.isNaN(parsed) ? Number.MAX_SAFE_INTEGER : parsed;
228
+ };
229
+ resolvedEntries.sort((a, b) => resolvedAtMs(a.record) - resolvedAtMs(b.record));
230
+ const evicted = resolvedEntries.slice(0, Math.max(0, resolvedEntries.length - PENDING_RESOLVED_CAP));
231
+ for (const entry of evicted) {
232
+ const current = table.get(entry.key);
233
+ if (!(current !== void 0 && (current.status === "approved" || current.status === "rejected") && current.resolvedAt === entry.record.resolvedAt)) continue;
234
+ await table.delete(entry.key).catch((error) => {
235
+ ctx.logger.warn(`evolution-state-domain: pending-cap eviction for "${entry.key}" failed (will retry on the next resolve): ${error instanceof Error ? error.message : String(error)}`);
236
+ });
237
+ }
238
+ }
239
+ const rawRecord = record;
208
240
  if (resolved.record === null) return {
209
- record: rawRecord === null ? null : { ...rawRecord },
241
+ record: rawRecord === null ? null : structuredClone(rawRecord),
210
242
  applied: false
211
243
  };
212
244
  return {
213
- record: { ...resolved.record },
245
+ record: structuredClone(resolved.record),
214
246
  applied: true
215
247
  };
216
248
  } catch (error) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-state-domain",
3
3
  "description": "storage-domain provider for evolution state (community build)",
4
- "version": "0.3.62",
4
+ "version": "0.3.64",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -36,13 +36,13 @@
36
36
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
37
37
  "@deepseek-ai/cordis": "^4.0.1",
38
38
  "@deepseek-ai/dsh-storage-domain": "^0.1.1-rc.2",
39
- "@lmzhen/dsh-evolution-state-storage": "^0.3.62"
39
+ "@lmzhen/dsh-evolution-state-storage": "^0.3.64"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
43
43
  "@deepseek-ai/dsh-storage-domain": "^0.1.1-rc.2",
44
44
  "@deepseek-ai/dsh-storage": "^0.1.1-rc.2",
45
45
  "@deepseek-ai/dsh-storage-json": "^0.1.1-rc.2",
46
- "@lmzhen/dsh-evolution-state-storage": "^0.3.62"
46
+ "@lmzhen/dsh-evolution-state-storage": "^0.3.64"
47
47
  }
48
48
  }