@lmzhen/dsh-evolution-approval 0.3.22 → 0.3.24
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 +11 -2
- package/lib/types/index.d.ts +14 -0
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -35,3 +35,5 @@ Independent of request-prefix construction. This package does not alter the asse
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
- `approve()` deduplicates concurrent approvals inside one process, and state providers resolve the pending record atomically. However, the replay runner executes **before** that atomic resolution, so two OS processes approving the same id can each perform the write once while only one process wins the audit transition. Run approvals from a single writer process, or make replay runners idempotent when multi-process approval is required.
|
|
38
|
+
- **Concurrent approve + reject on the same id (F-204).** Inside one process the dedupe keys are `approve:<id>` / `reject:<id>`, so the two paths are not serialized against each other. When an approve runner is slow, a reject resolves the still-executing record to `rejected` **without holding a claim**; the runner may then complete and the write can still land while the audit history reads `rejected` — the write effect, not the audit verdict, is what actually persists (`写效果以实际为准`). `reject` on an executing record reports this and asks you to verify the write state manually. Only reject a write after confirming no approve is in flight, or verify the write effect manually afterwards.
|
|
39
|
+
- **No staged-content freshness re-validation (F-328).** The staged record stores the `args` snapshot captured at request time and replays exactly those args, but does not record a content hash, so `approve()` does **not** re-check whether the on-disk skill/memory the write targets changed since staging. The write is applied as staged regardless. The pending surface (`/evolution pending --detail`) exposes the staged `args` so you can review what will actually be replayed before approving; there is no automatic drift warning if the target changed in the meantime.
|
package/lib/index.js
CHANGED
|
@@ -15,6 +15,15 @@ import z from "@deepseek-ai/schemastery";
|
|
|
15
15
|
*
|
|
16
16
|
* @module @lmzhen/dsh-evolution-approval
|
|
17
17
|
*/
|
|
18
|
+
/** The requesting session's effective policy (override ?? configured default);
|
|
19
|
+
* undefined when the approval service is not mounted or no session is
|
|
20
|
+
* available — callers keep their previous behavior. Single source (G4.8,
|
|
21
|
+
* F-341): the model tools each copied this helper; it lives here now. */
|
|
22
|
+
function effectiveSessionPolicy(ctx, session) {
|
|
23
|
+
const approval = ctx.get("approval");
|
|
24
|
+
if (!approval || session === void 0) return void 0;
|
|
25
|
+
return approval.overrideOf(session) ?? approval.config.policy ?? "ask";
|
|
26
|
+
}
|
|
18
27
|
var EvolutionApproval = class extends Service {
|
|
19
28
|
static inject = ["evolutionState"];
|
|
20
29
|
static Config = z.object({
|
|
@@ -120,7 +129,7 @@ var EvolutionApproval = class extends Service {
|
|
|
120
129
|
if (!await this.state().claimPending(id, claimId)) {
|
|
121
130
|
if ((await this.state().listPending("executing")).find((item) => item.id === id)) return (await this.state().tryResolvePending(id, "rejected")).applied ? {
|
|
122
131
|
ok: true,
|
|
123
|
-
message: `Rejected executing write "${id}" (
|
|
132
|
+
message: `Rejected executing write "${id}" (no claim held — this may race an in-flight approve runner; if the write already landed its effect stands as-is. Verify the write state manually).`
|
|
124
133
|
} : {
|
|
125
134
|
ok: false,
|
|
126
135
|
message: `Pending write "${id}" could not be rejected: it resolved concurrently.`
|
|
@@ -235,4 +244,4 @@ function normalizeSummary(input) {
|
|
|
235
244
|
return trimmed;
|
|
236
245
|
}
|
|
237
246
|
//#endregion
|
|
238
|
-
export { EvolutionApproval, EvolutionApproval as default };
|
|
247
|
+
export { EvolutionApproval, EvolutionApproval as default, effectiveSessionPolicy };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -69,6 +69,20 @@ export type ApprovalLike = {
|
|
|
69
69
|
message: string;
|
|
70
70
|
}>;
|
|
71
71
|
};
|
|
72
|
+
/** 0.3.23 (G4.8): the ONE shape of the platform approval-policy probe that
|
|
73
|
+
* `effectiveSessionPolicy` reads. The model tools used to copy this view
|
|
74
|
+
* locally (F-341). */
|
|
75
|
+
export interface ApprovalPolicyLike {
|
|
76
|
+
overrideOf(session: unknown): 'ask' | 'never' | undefined;
|
|
77
|
+
config: {
|
|
78
|
+
policy?: 'ask' | 'never';
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** The requesting session's effective policy (override ?? configured default);
|
|
82
|
+
* undefined when the approval service is not mounted or no session is
|
|
83
|
+
* available — callers keep their previous behavior. Single source (G4.8,
|
|
84
|
+
* F-341): the model tools each copied this helper; it lives here now. */
|
|
85
|
+
export declare function effectiveSessionPolicy(ctx: Context, session: unknown): 'ask' | 'never' | undefined;
|
|
72
86
|
declare module '@deepseek-ai/cordis' {
|
|
73
87
|
interface Context {
|
|
74
88
|
evolutionApproval: EvolutionApproval;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-approval",
|
|
3
3
|
"description": "Stage/pending approval service for Hermes-style self-evolution writes (community build)",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.24",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
37
37
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
38
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
39
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
38
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.24",
|
|
39
|
+
"@lmzhen/dsh-evolution-state": "^0.3.24"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
43
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
44
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
45
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
46
|
-
"@lmzhen/dsh-evolution-io-node": "^0.3.
|
|
47
|
-
"@lmzhen/dsh-evolution-state-json": "^0.3.
|
|
43
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.24",
|
|
44
|
+
"@lmzhen/dsh-evolution-state": "^0.3.24",
|
|
45
|
+
"@lmzhen/dsh-evolution-io": "^0.3.24",
|
|
46
|
+
"@lmzhen/dsh-evolution-io-node": "^0.3.24",
|
|
47
|
+
"@lmzhen/dsh-evolution-state-json": "^0.3.24"
|
|
48
48
|
}
|
|
49
49
|
}
|