create-principles-disciple 1.145.26 → 1.145.27
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/_release/product-identity.json +1 -1
- package/console/dist/server/models/RuleCandidateBindingConsoleModel.d.ts +26 -0
- package/console/dist/server/models/RuleCandidateBindingConsoleModel.js +309 -19
- package/console/dist/server/routes/rule-candidate-bindings.js +26 -1
- package/console/dist/shared/rule-candidate-binding-contract.d.ts +93 -8
- package/console/dist/shared/rule-candidate-binding-contract.js +4 -0
- package/console/dist/ui/api.d.ts +28 -0
- package/console/dist/ui/api.js +13 -1
- package/console/dist/ui/i18n/en.json +92 -20
- package/console/dist/ui/i18n/zh-CN.json +78 -6
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +29 -0
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +229 -3
- package/console/dist/ui/utils/rule-binding-validators.d.ts +5 -0
- package/console/dist/ui/utils/rule-binding-validators.js +149 -7
- package/console/dist/web/assets/app.css +6 -0
- package/console/dist/web/assets/app.js +32 -32
- package/core/dist/runtime-v2/golden-trace.d.ts.map +1 -1
- package/core/dist/runtime-v2/golden-trace.js +8 -1
- package/core/dist/runtime-v2/golden-trace.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +3 -1
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +2 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-intent-preflight.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-intent-preflight.js +26 -95
- package/core/dist/runtime-v2/internalization/artificer-intent-preflight.js.map +1 -1
- package/core/dist/runtime-v2/internalization/bash-risk.d.ts +32 -0
- package/core/dist/runtime-v2/internalization/bash-risk.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/bash-risk.js +785 -0
- package/core/dist/runtime-v2/internalization/bash-risk.js.map +1 -0
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +25 -2
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js +177 -14
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +14 -2
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.d.ts +47 -0
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.js +164 -3
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.js.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +9 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.js.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +39 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.js +59 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-source-correction.d.ts +60 -0
- package/core/dist/runtime-v2/internalization/rule-source-correction.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/rule-source-correction.js +214 -0
- package/core/dist/runtime-v2/internalization/rule-source-correction.js.map +1 -0
- package/core/dist/runtime-v2/internalization/rulecode-verification-obligations.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/rulecode-verification-obligations.js +65 -0
- package/core/dist/runtime-v2/internalization/rulecode-verification-obligations.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts +14 -2
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-output.js +57 -2
- package/core/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts +13 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js +15 -3
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-runner.d.ts +34 -0
- package/core/dist/runtime-v2/internalization/scribe-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-runner.js +128 -4
- package/core/dist/runtime-v2/internalization/scribe-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/textual-basis-anchor.d.ts +72 -0
- package/core/dist/runtime-v2/internalization/textual-basis-anchor.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/textual-basis-anchor.js +100 -0
- package/core/dist/runtime-v2/internalization/textual-basis-anchor.js.map +1 -0
- package/core/dist/runtime-v2/store/lifecycle/lease-manager.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/lifecycle/lease-manager.js +11 -2
- package/core/dist/runtime-v2/store/lifecycle/lease-manager.js.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js +26 -0
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -1
- package/core/dist/telemetry-event.d.ts +2 -2
- package/core/dist/telemetry-event.d.ts.map +1 -1
- package/core/dist/telemetry-event.js +5 -0
- package/core/dist/telemetry-event.js.map +1 -1
- package/core/package.json +5 -1
- package/host-runtime/dist/production-rulehost-gate.js +11 -1
- package/host-runtime/package.json +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js +32 -0
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/bundle.js +503 -490
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/package.json +2 -2
|
@@ -7,6 +7,19 @@ export declare class RuleCandidateBindingConsoleModel {
|
|
|
7
7
|
private readonly workspaceDir;
|
|
8
8
|
constructor(workspaceDir: string);
|
|
9
9
|
private ledger;
|
|
10
|
+
/** One bounded readonly batch read of the pain events behind the queue.
|
|
11
|
+
* `degraded` names an unreadable trajectory store so lookups that found
|
|
12
|
+
* nothing are labeled 不可读 rather than 未记录 (rc-9 — never misattribute). */
|
|
13
|
+
private painSources;
|
|
14
|
+
/** Identity stays with the ledger adapter (the identity authority); the
|
|
15
|
+
* principle entry / decidedAt come from the caller's single file snapshot.
|
|
16
|
+
* bindingRevision rides along so the source-correction preview can anchor
|
|
17
|
+
* its eligibility to the CURRENT binding (PRI-1048 R6 #4). */
|
|
18
|
+
private queueBinding;
|
|
19
|
+
/** PRI-1048 R6 #4: read-only eligibility preview for source-correct-once.
|
|
20
|
+
* Only the bound+blocked shape can offer it; the click-time authority
|
|
21
|
+
* (reviseRuleSourceOnce) re-checks everything server-side. */
|
|
22
|
+
private sourceCorrectionPreview;
|
|
10
23
|
list(): Promise<RuleBindingQueueView>;
|
|
11
24
|
review(candidateId: string, search: string): Promise<{
|
|
12
25
|
ok: true;
|
|
@@ -37,4 +50,17 @@ export declare class RuleCandidateBindingConsoleModel {
|
|
|
37
50
|
scribeTaskId: string;
|
|
38
51
|
taskRevisionEpoch: number;
|
|
39
52
|
}>;
|
|
53
|
+
/**
|
|
54
|
+
* SPEC-PRI-1047 修复 B: 认证入口的一次 Owner source-correction。区别于
|
|
55
|
+
* revise(binding 修订预算):这是「修正上游材料」的独立一次预算,回执
|
|
56
|
+
* 绑定真实 Owner actor/request。调用侧(路由)负责 ownerIdentity 门。
|
|
57
|
+
*/
|
|
58
|
+
correctSource(candidateId: string, input: {
|
|
59
|
+
expectedBindingRevision: number;
|
|
60
|
+
expectedScribeTaskId: string;
|
|
61
|
+
expectedArtificerTaskId: string;
|
|
62
|
+
expectedScribeArtifactDigest: string;
|
|
63
|
+
reason: string;
|
|
64
|
+
requestId: string;
|
|
65
|
+
}, actorId: string): Promise<import("@principles/core/runtime-v2").ReviseRuleSourceOnceResult>;
|
|
40
66
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import { createRuntimeStateHandle, PrincipleTreeLedgerAdapter, reviseRuleBindingOnce, resolveRuleBindingRevisionTarget, reviseRuleSourceOnce, previewRuleSourceCorrection, hydratePITaskRecord, candidateIdFromDreamerSeed, } from '@principles/core/runtime-v2';
|
|
5
|
+
import { readLedgerFileState } from '@principles/core/principle-tree-ledger';
|
|
4
6
|
import { ActivationsConsoleModel } from './ActivationsConsoleModel.js';
|
|
5
7
|
function record(value) {
|
|
6
8
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -8,6 +10,108 @@ function record(value) {
|
|
|
8
10
|
function stringField(value, key) {
|
|
9
11
|
return record(value) && typeof value[key] === 'string' ? value[key] : '';
|
|
10
12
|
}
|
|
13
|
+
/** Internalization chain order; the queue projection walks it read-only. */
|
|
14
|
+
const CHAIN_KINDS = ['dreamer', 'philosopher', 'scribe', 'artificer', 'evaluator', 'rollout_reviewer'];
|
|
15
|
+
/** PRI-1048: bounded queue — a governance workspace carries tens of candidates;
|
|
16
|
+
* the cap keeps the derived scan bounded and the response honest via `truncated`. */
|
|
17
|
+
const MAX_QUEUE_ITEMS = 200;
|
|
18
|
+
function buildChainContext(allTasks) {
|
|
19
|
+
const byId = new Map(allTasks.map(task => [task.taskId, task]));
|
|
20
|
+
const dreamersByCandidate = new Map();
|
|
21
|
+
const dependentsByTaskId = new Map();
|
|
22
|
+
for (const task of allTasks) {
|
|
23
|
+
if (task.taskKind === 'dreamer') {
|
|
24
|
+
const seed = candidateIdFromDreamerSeed(task.diagnosticJson ?? null);
|
|
25
|
+
if (seed) {
|
|
26
|
+
const list = dreamersByCandidate.get(seed) ?? [];
|
|
27
|
+
list.push(task);
|
|
28
|
+
dreamersByCandidate.set(seed, list);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const pi = hydratePITaskRecord(task);
|
|
32
|
+
if (!pi)
|
|
33
|
+
continue;
|
|
34
|
+
for (const dependencyId of pi.dependencyTaskIds) {
|
|
35
|
+
const list = dependentsByTaskId.get(dependencyId) ?? [];
|
|
36
|
+
list.push(task);
|
|
37
|
+
dependentsByTaskId.set(dependencyId, list);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { byId, dreamersByCandidate, dependentsByTaskId };
|
|
41
|
+
}
|
|
42
|
+
function walkChain(dreamer, context) {
|
|
43
|
+
let current = dreamer;
|
|
44
|
+
let kind = 'dreamer';
|
|
45
|
+
for (;;) {
|
|
46
|
+
if (!current)
|
|
47
|
+
return { stage: 'advanced', stageKind: kind, reasonCode: null, detail: null };
|
|
48
|
+
if (current.status === 'needs_human_review' || current.status === 'failed') {
|
|
49
|
+
const pi = hydratePITaskRecord(current);
|
|
50
|
+
const review = pi?.humanReviewContext;
|
|
51
|
+
return {
|
|
52
|
+
stage: 'blocked', stageKind: kind,
|
|
53
|
+
reasonCode: review && typeof review.reasonCode === 'string' ? review.reasonCode : null,
|
|
54
|
+
detail: review && typeof review.detail === 'string' ? review.detail : (current.lastError ?? null),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (current.status !== 'succeeded')
|
|
58
|
+
return { stage: 'in_progress', stageKind: kind, reasonCode: null, detail: null };
|
|
59
|
+
const nextIndex = CHAIN_KINDS.indexOf(kind) + 1;
|
|
60
|
+
const nextKind = nextIndex < CHAIN_KINDS.length ? CHAIN_KINDS[nextIndex] : undefined;
|
|
61
|
+
if (!nextKind)
|
|
62
|
+
return { stage: 'advanced', stageKind: kind, reasonCode: null, detail: null };
|
|
63
|
+
const next = (context.dependentsByTaskId.get(current.taskId) ?? []).find(task => task.taskKind === nextKind);
|
|
64
|
+
if (!next)
|
|
65
|
+
return { stage: 'advanced', stageKind: kind, reasonCode: null, detail: null };
|
|
66
|
+
current = next;
|
|
67
|
+
kind = nextKind;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function deriveGeneration(candidateId, context) {
|
|
71
|
+
const dreamers = context.dreamersByCandidate.get(candidateId) ?? [];
|
|
72
|
+
if (dreamers.length === 0)
|
|
73
|
+
return { stage: 'not_built', stageKind: null, reasonCode: null, detail: null };
|
|
74
|
+
const walks = dreamers.map(dreamer => walkChain(dreamer, context));
|
|
75
|
+
const [first] = walks;
|
|
76
|
+
if (!first)
|
|
77
|
+
return { stage: 'ambiguous', stageKind: null, reasonCode: null, detail: null };
|
|
78
|
+
const sameWalk = (a, b) => a.stage === b.stage && a.stageKind === b.stageKind && a.reasonCode === b.reasonCode;
|
|
79
|
+
if (walks.every(walk => sameWalk(walk, first)))
|
|
80
|
+
return first;
|
|
81
|
+
return { stage: 'ambiguous', stageKind: null, reasonCode: null, detail: null };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Real backend eligibility only: the production resolver plus the exact
|
|
85
|
+
* budget rule reviseRuleBindingOnce enforces on the same scribe task. The
|
|
86
|
+
* revise-once route still authoritatively re-checks at click time.
|
|
87
|
+
*/
|
|
88
|
+
async function deriveResume(stateManager, candidateId) {
|
|
89
|
+
const target = await resolveRuleBindingRevisionTarget(stateManager, candidateId);
|
|
90
|
+
if (target.status !== 'ready')
|
|
91
|
+
return { status: 'refused', reason: target.reason, scribeTaskId: null, taskRevisionEpoch: null };
|
|
92
|
+
const scribe = await stateManager.getTask(target.scribeTaskId);
|
|
93
|
+
const pi = scribe ? hydratePITaskRecord(scribe) : null;
|
|
94
|
+
if (!scribe || !pi)
|
|
95
|
+
return { status: 'refused', reason: 'scribe_missing', scribeTaskId: target.scribeTaskId, taskRevisionEpoch: target.taskRevisionEpoch };
|
|
96
|
+
if (pi.ruleBindingRevisionCauseId || pi.revisionCauseId?.startsWith('rule-binding:')) {
|
|
97
|
+
return { status: 'refused', reason: 'revision_budget_exhausted', scribeTaskId: target.scribeTaskId, taskRevisionEpoch: target.taskRevisionEpoch };
|
|
98
|
+
}
|
|
99
|
+
return { status: 'ready', reason: null, scribeTaskId: target.scribeTaskId, taskRevisionEpoch: target.taskRevisionEpoch };
|
|
100
|
+
}
|
|
101
|
+
/** Uses the caller's ONE ledger snapshot: decidedAt + principle entry, no extra file read. */
|
|
102
|
+
function boundPrincipleView(state, lookup) {
|
|
103
|
+
if (state.availability.status === 'unreadable')
|
|
104
|
+
return null;
|
|
105
|
+
const principle = Object.hasOwn(state.ledger.tree.principles, lookup.principleId) ? state.ledger.tree.principles[lookup.principleId] : undefined;
|
|
106
|
+
if (!principle)
|
|
107
|
+
return null;
|
|
108
|
+
const binding = Object.hasOwn(state.ledger.tree.ruleCandidateBindings ?? {}, lookup.candidateId)
|
|
109
|
+
? state.ledger.tree.ruleCandidateBindings?.[lookup.candidateId]?.revisions.at(-1) : undefined;
|
|
110
|
+
return {
|
|
111
|
+
principleId: lookup.principleId, text: principle.text, status: principle.status,
|
|
112
|
+
version: principle.version, revision: lookup.revision, decidedAt: binding?.decidedAt ?? '',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
11
115
|
/** Derived review only. Binding authority stays inside the locked core Ledger writer. */
|
|
12
116
|
export class RuleCandidateBindingConsoleModel {
|
|
13
117
|
workspaceDir;
|
|
@@ -32,31 +136,172 @@ export class RuleCandidateBindingConsoleModel {
|
|
|
32
136
|
},
|
|
33
137
|
});
|
|
34
138
|
}
|
|
139
|
+
/** One bounded readonly batch read of the pain events behind the queue.
|
|
140
|
+
* `degraded` names an unreadable trajectory store so lookups that found
|
|
141
|
+
* nothing are labeled 不可读 rather than 未记录 (rc-9 — never misattribute). */
|
|
142
|
+
painSources(painIds) {
|
|
143
|
+
const result = new Map();
|
|
144
|
+
const distinct = [...new Set(painIds.filter(id => id !== ''))];
|
|
145
|
+
if (distinct.length === 0)
|
|
146
|
+
return { sources: result, degraded: null };
|
|
147
|
+
const dbPath = path.join(this.workspaceDir, '.state', 'trajectory.db');
|
|
148
|
+
if (!existsSync(dbPath))
|
|
149
|
+
return { sources: result, degraded: null };
|
|
150
|
+
let db = null;
|
|
151
|
+
try {
|
|
152
|
+
db = new Database(dbPath, { readonly: true });
|
|
153
|
+
const placeholders = distinct.map(() => '?').join(',');
|
|
154
|
+
const rows = db.prepare(`SELECT canonical_pain_id AS painId, source, text, created_at AS createdAt
|
|
155
|
+
FROM pain_events WHERE canonical_pain_id IN (${placeholders})`).all(...distinct);
|
|
156
|
+
// Multiple events may share a canonical id; keep the newest (same policy
|
|
157
|
+
// as the pain list ordering — newest first).
|
|
158
|
+
for (const row of rows) {
|
|
159
|
+
if (!record(row))
|
|
160
|
+
continue;
|
|
161
|
+
const painId = typeof row.painId === 'string' ? row.painId : '';
|
|
162
|
+
if (painId === '')
|
|
163
|
+
continue;
|
|
164
|
+
const existing = result.get(painId);
|
|
165
|
+
const createdAt = typeof row.createdAt === 'string' ? row.createdAt : null;
|
|
166
|
+
if (existing && existing.createdAt && createdAt && existing.createdAt >= createdAt)
|
|
167
|
+
continue;
|
|
168
|
+
result.set(painId, {
|
|
169
|
+
painId,
|
|
170
|
+
text: typeof row.text === 'string' && row.text.trim() !== '' ? row.text : null,
|
|
171
|
+
source: typeof row.source === 'string' ? row.source : 'unknown',
|
|
172
|
+
createdAt,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Read failure must not masquerade as never-recorded: the degraded flag
|
|
178
|
+
// turns missing lookups into 记录暂不可读 (rc-9 observable degradation).
|
|
179
|
+
return { sources: new Map(), degraded: 'trajectory_unreadable' };
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
db?.close();
|
|
183
|
+
}
|
|
184
|
+
return { sources: result, degraded: null };
|
|
185
|
+
}
|
|
186
|
+
/** Identity stays with the ledger adapter (the identity authority); the
|
|
187
|
+
* principle entry / decidedAt come from the caller's single file snapshot.
|
|
188
|
+
* bindingRevision rides along so the source-correction preview can anchor
|
|
189
|
+
* its eligibility to the CURRENT binding (PRI-1048 R6 #4). */
|
|
190
|
+
queueBinding(stateManager, ledgerState, candidateId) {
|
|
191
|
+
const identity = this.ledger(stateManager).resolveCandidatePrincipleIdentity(candidateId, 'rule');
|
|
192
|
+
if (identity.status === 'resolved') {
|
|
193
|
+
const view = boundPrincipleView(ledgerState, { candidateId, principleId: identity.principleId, revision: identity.bindingRevision ?? 0 });
|
|
194
|
+
if (view)
|
|
195
|
+
return { view: { status: 'bound', principle: view }, bindingRevision: identity.bindingRevision ?? null };
|
|
196
|
+
// Bound in the ledger but the principle entry itself is unreadable or
|
|
197
|
+
// gone — surface as attention, never silently unlinked.
|
|
198
|
+
return { view: { status: 'attention', reason: 'bound_principle_unreadable' }, bindingRevision: identity.bindingRevision ?? null };
|
|
199
|
+
}
|
|
200
|
+
if (identity.reason === 'missing')
|
|
201
|
+
return { view: { status: 'unlinked' }, bindingRevision: null };
|
|
202
|
+
if (identity.reason === 'binding_revoked')
|
|
203
|
+
return { view: { status: 'binding_revoked' }, bindingRevision: null };
|
|
204
|
+
return { view: { status: 'attention', reason: identity.reason }, bindingRevision: null };
|
|
205
|
+
}
|
|
206
|
+
/** PRI-1048 R6 #4: read-only eligibility preview for source-correct-once.
|
|
207
|
+
* Only the bound+blocked shape can offer it; the click-time authority
|
|
208
|
+
* (reviseRuleSourceOnce) re-checks everything server-side. */
|
|
209
|
+
async sourceCorrectionPreview(stateManager, candidateId, bindingRevision) {
|
|
210
|
+
const ledger = this.ledger(stateManager);
|
|
211
|
+
const preview = await previewRuleSourceCorrection({
|
|
212
|
+
stateManager,
|
|
213
|
+
ledger: { resolveForCandidate: async (id) => ledger.resolveCandidatePrincipleIdentity(id, 'rule') },
|
|
214
|
+
candidateId,
|
|
215
|
+
expectedBindingRevision: bindingRevision,
|
|
216
|
+
});
|
|
217
|
+
return preview.status === 'ready'
|
|
218
|
+
? {
|
|
219
|
+
status: 'ready', reason: null,
|
|
220
|
+
scribeTaskId: preview.scribeTaskId, artificerTaskId: preview.artificerTaskId,
|
|
221
|
+
scribeArtifactDigest: preview.scribeArtifactDigest, expectedBindingRevision: preview.expectedBindingRevision,
|
|
222
|
+
}
|
|
223
|
+
: { status: 'unavailable', reason: preview.reason, scribeTaskId: null, artificerTaskId: null, scribeArtifactDigest: null, expectedBindingRevision: null };
|
|
224
|
+
}
|
|
35
225
|
async list() {
|
|
36
226
|
// A fresh workspace with no state.db simply has no binding queue yet;
|
|
37
227
|
// any other storage problem still surfaces as an error (503 at the route).
|
|
38
|
-
if (!existsSync(path.join(this.workspaceDir, '.pd', 'state.db')))
|
|
39
|
-
return { items: [] };
|
|
228
|
+
if (!existsSync(path.join(this.workspaceDir, '.pd', 'state.db'))) {
|
|
229
|
+
return { items: [], summary: { painGroups: 0, candidates: 0, bound: 0, unlinked: 0, blocked: 0 }, truncated: false };
|
|
230
|
+
}
|
|
40
231
|
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
41
232
|
try {
|
|
42
|
-
const
|
|
233
|
+
const { stateManager } = handle;
|
|
234
|
+
const allTasks = await stateManager.listTasks();
|
|
235
|
+
const taskById = new Map(allTasks.map(task => [task.taskId, task]));
|
|
43
236
|
// Split diagnoses commit their rule candidates on diag_router sub-tasks;
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
for (const candidate of await handle.stateManager.getCandidatesByTaskId(task.taskId)) {
|
|
237
|
+
// getCandidatesByTaskId already spans "own + child" tasks, so traversing
|
|
238
|
+
// BOTH task lists surfaces router-committed candidates twice. The queue
|
|
239
|
+
// aggregation owner (this model) dedupes by canonical candidateId; the
|
|
240
|
+
// shared store query keeps its semantics for every other consumer.
|
|
241
|
+
const diagnosisTasks = allTasks.filter(task => task.taskKind === 'diagnostician' || task.taskKind === 'diag_router');
|
|
242
|
+
const collected = new Map();
|
|
243
|
+
for (const task of diagnosisTasks) {
|
|
244
|
+
for (const candidate of await stateManager.getCandidatesByTaskId(task.taskId)) {
|
|
53
245
|
if (candidate.rawRecommendationKind !== 'rule')
|
|
54
246
|
continue;
|
|
55
|
-
|
|
56
|
-
|
|
247
|
+
if (collected.has(candidate.candidateId))
|
|
248
|
+
continue;
|
|
249
|
+
// Source pain: a router candidate resolves through its parent
|
|
250
|
+
// diagnostician; a direct candidate reads its own inputRef.
|
|
251
|
+
const candidateTask = taskById.get(candidate.taskId) ?? task;
|
|
252
|
+
const parentTask = candidateTask.taskKind === 'diag_router' && candidateTask.inputRef
|
|
253
|
+
? taskById.get(candidateTask.inputRef) : undefined;
|
|
254
|
+
const diagnosisTaskId = parentTask?.taskId ?? candidateTask.taskId;
|
|
255
|
+
const painId = (parentTask?.inputRef ?? candidateTask.inputRef) ?? '';
|
|
256
|
+
collected.set(candidate.candidateId, {
|
|
257
|
+
candidateId: candidate.candidateId,
|
|
258
|
+
text: candidate.description || candidate.title,
|
|
259
|
+
painId, diagnosisTaskId,
|
|
260
|
+
});
|
|
57
261
|
}
|
|
58
262
|
}
|
|
59
|
-
|
|
263
|
+
const truncated = collected.size > MAX_QUEUE_ITEMS;
|
|
264
|
+
const entries = [...collected.values()].slice(0, MAX_QUEUE_ITEMS);
|
|
265
|
+
const painLookup = this.painSources(entries.map(entry => entry.painId));
|
|
266
|
+
const chainContext = buildChainContext(allTasks);
|
|
267
|
+
const ledgerState = readLedgerFileState(path.join(this.workspaceDir, '.state'));
|
|
268
|
+
const items = [];
|
|
269
|
+
for (const entry of entries) {
|
|
270
|
+
const diagnosisTask = chainContext.byId.get(entry.diagnosisTaskId) ?? null;
|
|
271
|
+
const { view: binding, bindingRevision } = this.queueBinding(stateManager, ledgerState, entry.candidateId);
|
|
272
|
+
const generation = binding.status === 'unlinked' ? null : deriveGeneration(entry.candidateId, chainContext);
|
|
273
|
+
const resume = binding.status === 'bound' ? await deriveResume(stateManager, entry.candidateId) : null;
|
|
274
|
+
// PRI-1048 R6 #4: the source-correction entry applies to the bound+blocked
|
|
275
|
+
// shape only (the binding revision budget is typically already spent there).
|
|
276
|
+
const sourceCorrection = binding.status === 'bound' && generation?.stage === 'blocked' && bindingRevision !== null
|
|
277
|
+
? await this.sourceCorrectionPreview(stateManager, entry.candidateId, bindingRevision)
|
|
278
|
+
: null;
|
|
279
|
+
items.push({
|
|
280
|
+
candidateId: entry.candidateId,
|
|
281
|
+
text: entry.text,
|
|
282
|
+
pain: painLookup.sources.get(entry.painId) ?? {
|
|
283
|
+
painId: entry.painId, text: null,
|
|
284
|
+
source: painLookup.degraded === 'trajectory_unreadable' && entry.painId !== '' ? 'unreadable' : 'unknown',
|
|
285
|
+
createdAt: null,
|
|
286
|
+
},
|
|
287
|
+
diagnosisStatus: diagnosisTask?.status ?? 'unknown',
|
|
288
|
+
binding,
|
|
289
|
+
generation,
|
|
290
|
+
resume,
|
|
291
|
+
sourceCorrection,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
items,
|
|
296
|
+
summary: {
|
|
297
|
+
painGroups: new Set(items.map(item => item.pain.painId === '' ? `candidate:${item.candidateId}` : item.pain.painId)).size,
|
|
298
|
+
candidates: items.length,
|
|
299
|
+
bound: items.filter(item => item.binding.status === 'bound').length,
|
|
300
|
+
unlinked: items.filter(item => item.binding.status === 'unlinked').length,
|
|
301
|
+
blocked: items.filter(item => item.generation?.stage === 'blocked').length,
|
|
302
|
+
},
|
|
303
|
+
truncated,
|
|
304
|
+
};
|
|
60
305
|
}
|
|
61
306
|
finally {
|
|
62
307
|
await handle.close();
|
|
@@ -65,20 +310,44 @@ export class RuleCandidateBindingConsoleModel {
|
|
|
65
310
|
async review(candidateId, search) {
|
|
66
311
|
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
67
312
|
try {
|
|
68
|
-
const
|
|
313
|
+
const { stateManager } = handle;
|
|
314
|
+
const result = await this.ledger(stateManager).createRuleCandidateBindingReview(candidateId, { search, limit: 20 });
|
|
69
315
|
if (!result.ok)
|
|
70
316
|
return result;
|
|
71
317
|
const { candidateMaterial: material } = result;
|
|
318
|
+
const parentTaskInputRef = stringField(Reflect.get(material, 'parentTask'), 'inputRef');
|
|
319
|
+
const painId = parentTaskInputRef || stringField(material.task, 'inputRef');
|
|
320
|
+
const painLookup = this.painSources([painId]);
|
|
321
|
+
const pain = painLookup.sources.get(painId) ?? {
|
|
322
|
+
painId, text: null,
|
|
323
|
+
source: painLookup.degraded === 'trajectory_unreadable' && painId !== '' ? 'unreadable' : 'unknown',
|
|
324
|
+
createdAt: null,
|
|
325
|
+
};
|
|
326
|
+
const { currentBinding } = result;
|
|
327
|
+
const isBound = currentBinding?.action === 'bind';
|
|
328
|
+
const boundPrinciple = isBound && currentBinding
|
|
329
|
+
? boundPrincipleView(readLedgerFileState(path.join(this.workspaceDir, '.state')), { candidateId, principleId: currentBinding.principleId, revision: currentBinding.revision })
|
|
330
|
+
: null;
|
|
331
|
+
const chainContext = buildChainContext(await stateManager.listTasks());
|
|
332
|
+
const generation = isBound ? deriveGeneration(candidateId, chainContext) : null;
|
|
333
|
+
const resume = isBound ? await deriveResume(stateManager, candidateId) : null;
|
|
334
|
+
const sourceCorrection = isBound && generation?.stage === 'blocked' && currentBinding
|
|
335
|
+
? await this.sourceCorrectionPreview(stateManager, candidateId, currentBinding.revision)
|
|
336
|
+
: null;
|
|
72
337
|
return { ok: true, review: {
|
|
73
338
|
candidateId, candidateText: stringField(material.candidate, 'description') || stringField(material.candidate, 'title'),
|
|
74
|
-
|
|
339
|
+
sourcePain: pain,
|
|
75
340
|
evidence: stringField(material.artifact, 'contentJson') || stringField(material.candidate, 'sourceRecommendationJson'),
|
|
76
341
|
candidateDigest: result.reviewedCandidateDigest,
|
|
77
342
|
currentRevision: result.currentRevision,
|
|
78
|
-
currentBinding
|
|
343
|
+
currentBinding,
|
|
344
|
+
boundPrinciple,
|
|
79
345
|
eligibleTargets: result.eligibleTargets.map(({ principle, reviewedPrincipleDigest }) => ({
|
|
80
346
|
principleId: principle.id, text: principle.text, status: principle.status, version: principle.version, digest: reviewedPrincipleDigest,
|
|
81
347
|
})),
|
|
348
|
+
generation,
|
|
349
|
+
resume,
|
|
350
|
+
sourceCorrection,
|
|
82
351
|
resumeNotice: '关联后自动启动一次现有配置的正文修订与代码生成、验证;沿用现有调用预算和超时。失败会保留关联与旧工件,不会自动循环,也不会批准或启用规则。',
|
|
83
352
|
} };
|
|
84
353
|
}
|
|
@@ -127,4 +396,25 @@ export class RuleCandidateBindingConsoleModel {
|
|
|
127
396
|
await handle.close();
|
|
128
397
|
}
|
|
129
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* SPEC-PRI-1047 修复 B: 认证入口的一次 Owner source-correction。区别于
|
|
401
|
+
* revise(binding 修订预算):这是「修正上游材料」的独立一次预算,回执
|
|
402
|
+
* 绑定真实 Owner actor/request。调用侧(路由)负责 ownerIdentity 门。
|
|
403
|
+
*/
|
|
404
|
+
async correctSource(candidateId, input, actorId) {
|
|
405
|
+
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir });
|
|
406
|
+
try {
|
|
407
|
+
const ledger = this.ledger(handle.stateManager);
|
|
408
|
+
return await reviseRuleSourceOnce({
|
|
409
|
+
stateManager: handle.stateManager,
|
|
410
|
+
ledger: { resolveForCandidate: async (id) => ledger.resolveCandidatePrincipleIdentity(id, 'rule') },
|
|
411
|
+
candidateId,
|
|
412
|
+
...input,
|
|
413
|
+
actor: actorId,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
await handle.close();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
130
420
|
}
|
|
@@ -43,7 +43,7 @@ export async function handleRuleCandidateBindingsRoute(req, res, ctx) {
|
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
const model = new RuleCandidateBindingConsoleModel(ctx.workspaceDir);
|
|
46
|
-
const match = /^\/([^/]+)(?:\/(review|revise-once))?$/.exec(ctx.subPath);
|
|
46
|
+
const match = /^\/([^/]+)(?:\/(review|revise-once|source-correct-once))?$/.exec(ctx.subPath);
|
|
47
47
|
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
48
48
|
try {
|
|
49
49
|
if ((ctx.subPath === '' || ctx.subPath === '/') && req.method === 'GET') {
|
|
@@ -84,6 +84,31 @@ export async function handleRuleCandidateBindingsRoute(req, res, ctx) {
|
|
|
84
84
|
sendBadRequest(res, '请求必须是有效的 JSON。');
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
|
+
if (match[2] === 'source-correct-once') {
|
|
88
|
+
// SPEC-PRI-1047: one bounded Owner source-correction per candidate. Closed
|
|
89
|
+
// field set: chain identity + digest precondition + reason/requestId —
|
|
90
|
+
// never identity-fabrication or approval fields.
|
|
91
|
+
if (!closed(raw, ['expectedBindingRevision', 'expectedScribeTaskId', 'expectedArtificerTaskId', 'expectedScribeArtifactDigest', 'reason', 'requestId'])
|
|
92
|
+
|| !revision(raw.expectedBindingRevision) || raw.expectedBindingRevision < 1
|
|
93
|
+
|| !text(raw.expectedScribeTaskId, 512) || !text(raw.expectedArtificerTaskId, 512)
|
|
94
|
+
|| !digest(raw.expectedScribeArtifactDigest) || !text(raw.reason, 2000) || !text(raw.requestId, 200)) {
|
|
95
|
+
sendBadRequest(res, '请提交当前关联、原候选链任务与工件摘要;不接受身份或批准字段。');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const result = await model.correctSource(candidateId, {
|
|
99
|
+
expectedBindingRevision: raw.expectedBindingRevision,
|
|
100
|
+
expectedScribeTaskId: raw.expectedScribeTaskId,
|
|
101
|
+
expectedArtificerTaskId: raw.expectedArtificerTaskId,
|
|
102
|
+
expectedScribeArtifactDigest: raw.expectedScribeArtifactDigest,
|
|
103
|
+
reason: raw.reason,
|
|
104
|
+
requestId: raw.requestId,
|
|
105
|
+
}, ctx.ownerIdentity.ownerId);
|
|
106
|
+
if (result.status === 'refused')
|
|
107
|
+
failure(res, result);
|
|
108
|
+
else
|
|
109
|
+
sendSuccess(res, result);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
87
112
|
if (match[2] === 'revise-once') {
|
|
88
113
|
if (!closed(raw, ['expectedBindingRevision', 'expectedScribeTaskId', 'expectedTaskRevisionEpoch', 'requestId'])
|
|
89
114
|
|| !revision(raw.expectedBindingRevision) || raw.expectedBindingRevision < 1
|
|
@@ -1,3 +1,91 @@
|
|
|
1
|
+
/** Owner-facing projection DTOs for the rule-candidate binding queue (PRI-1048).
|
|
2
|
+
* Derived read-only views over existing authorities (state.db tasks/candidates,
|
|
3
|
+
* trajectory.db pain_events, the principle ledger, the internalization chain).
|
|
4
|
+
* No new persisted state; the Ledger remains the only binding authority. */
|
|
5
|
+
/** Which owner feedback produced the candidate. Text is null when the pain
|
|
6
|
+
* record is gone — the UI must show 未记录, never fabricate a quote. */
|
|
7
|
+
export interface RuleBindingPainSourceView {
|
|
8
|
+
painId: string;
|
|
9
|
+
text: string | null;
|
|
10
|
+
source: string;
|
|
11
|
+
createdAt: string | null;
|
|
12
|
+
}
|
|
13
|
+
/** The formal principle a candidate is currently bound to (ledger authority). */
|
|
14
|
+
export interface RuleBindingBoundPrincipleView {
|
|
15
|
+
principleId: string;
|
|
16
|
+
text: string;
|
|
17
|
+
status: string;
|
|
18
|
+
version: number;
|
|
19
|
+
revision: number;
|
|
20
|
+
decidedAt: string;
|
|
21
|
+
}
|
|
22
|
+
/** Where the bound candidate's regeneration chain stands. `stageKind` names the
|
|
23
|
+
* deepest internalization task reached ('scribe', 'artificer', …). Blocked
|
|
24
|
+
* carries the server's reasonCode (e.g. textual_basis_unanchored) verbatim. */
|
|
25
|
+
export interface RuleBindingGenerationView {
|
|
26
|
+
stage: 'not_built' | 'in_progress' | 'blocked' | 'advanced' | 'ambiguous';
|
|
27
|
+
stageKind: string | null;
|
|
28
|
+
reasonCode: string | null;
|
|
29
|
+
detail: string | null;
|
|
30
|
+
}
|
|
31
|
+
/** Real backend revision eligibility, resolved by the production resolver
|
|
32
|
+
* (resolveRuleBindingRevisionTarget + the same budget rule reviseRuleBindingOnce
|
|
33
|
+
* enforces). The UI may only offer 修订并继续 when status === 'ready'. */
|
|
34
|
+
export interface RuleBindingResumeView {
|
|
35
|
+
status: 'ready' | 'refused';
|
|
36
|
+
reason: string | null;
|
|
37
|
+
scribeTaskId: string | null;
|
|
38
|
+
/** CAS input for the revise-once request (ready only). */
|
|
39
|
+
taskRevisionEpoch: number | null;
|
|
40
|
+
}
|
|
41
|
+
/** PRI-1048 (Owner review R6 #4): read-only eligibility preview for the
|
|
42
|
+
* source-correct-once capability (PRI-1047) — the bounded one-shot source
|
|
43
|
+
* revision that applies when the Artificer stopped for a SOURCE-material
|
|
44
|
+
* defect and the binding revision budget is spent. Click-time authority
|
|
45
|
+
* stays with reviseRuleSourceOnce on the server. */
|
|
46
|
+
export interface RuleBindingSourceCorrectionView {
|
|
47
|
+
status: 'ready' | 'unavailable';
|
|
48
|
+
reason: string | null;
|
|
49
|
+
/** CAS inputs for the source-correct-once request (ready only). */
|
|
50
|
+
scribeTaskId: string | null;
|
|
51
|
+
artificerTaskId: string | null;
|
|
52
|
+
scribeArtifactDigest: string | null;
|
|
53
|
+
expectedBindingRevision: number | null;
|
|
54
|
+
}
|
|
55
|
+
export type RuleBindingQueueBindingView = {
|
|
56
|
+
status: 'unlinked';
|
|
57
|
+
} | {
|
|
58
|
+
status: 'bound';
|
|
59
|
+
principle: RuleBindingBoundPrincipleView;
|
|
60
|
+
} | {
|
|
61
|
+
status: 'binding_revoked';
|
|
62
|
+
} | {
|
|
63
|
+
status: 'attention';
|
|
64
|
+
reason: string;
|
|
65
|
+
};
|
|
66
|
+
export interface RuleBindingQueueItem {
|
|
67
|
+
candidateId: string;
|
|
68
|
+
text: string;
|
|
69
|
+
pain: RuleBindingPainSourceView;
|
|
70
|
+
diagnosisStatus: string;
|
|
71
|
+
binding: RuleBindingQueueBindingView;
|
|
72
|
+
generation: RuleBindingGenerationView | null;
|
|
73
|
+
resume: RuleBindingResumeView | null;
|
|
74
|
+
/** PRI-1048 R6 #4: non-null only when bound (null = the capability does not apply). */
|
|
75
|
+
sourceCorrection: RuleBindingSourceCorrectionView | null;
|
|
76
|
+
}
|
|
77
|
+
export interface RuleBindingQueueSummary {
|
|
78
|
+
painGroups: number;
|
|
79
|
+
candidates: number;
|
|
80
|
+
bound: number;
|
|
81
|
+
unlinked: number;
|
|
82
|
+
blocked: number;
|
|
83
|
+
}
|
|
84
|
+
export interface RuleBindingQueueView {
|
|
85
|
+
items: RuleBindingQueueItem[];
|
|
86
|
+
summary: RuleBindingQueueSummary;
|
|
87
|
+
truncated: boolean;
|
|
88
|
+
}
|
|
1
89
|
export interface RuleBindingTargetView {
|
|
2
90
|
principleId: string;
|
|
3
91
|
text: string;
|
|
@@ -8,7 +96,7 @@ export interface RuleBindingTargetView {
|
|
|
8
96
|
export interface RuleBindingReviewView {
|
|
9
97
|
candidateId: string;
|
|
10
98
|
candidateText: string;
|
|
11
|
-
|
|
99
|
+
sourcePain: RuleBindingPainSourceView;
|
|
12
100
|
evidence: string;
|
|
13
101
|
candidateDigest: string;
|
|
14
102
|
currentRevision: number;
|
|
@@ -18,13 +106,10 @@ export interface RuleBindingReviewView {
|
|
|
18
106
|
reason: string;
|
|
19
107
|
revision: number;
|
|
20
108
|
} | null;
|
|
109
|
+
boundPrinciple: RuleBindingBoundPrincipleView | null;
|
|
21
110
|
eligibleTargets: RuleBindingTargetView[];
|
|
111
|
+
generation: RuleBindingGenerationView | null;
|
|
112
|
+
resume: RuleBindingResumeView | null;
|
|
113
|
+
sourceCorrection: RuleBindingSourceCorrectionView | null;
|
|
22
114
|
resumeNotice: string;
|
|
23
115
|
}
|
|
24
|
-
export interface RuleBindingQueueView {
|
|
25
|
-
items: {
|
|
26
|
-
candidateId: string;
|
|
27
|
-
text: string;
|
|
28
|
-
reason: string;
|
|
29
|
-
}[];
|
|
30
|
-
}
|
|
@@ -1 +1,5 @@
|
|
|
1
|
+
/** Owner-facing projection DTOs for the rule-candidate binding queue (PRI-1048).
|
|
2
|
+
* Derived read-only views over existing authorities (state.db tasks/candidates,
|
|
3
|
+
* trajectory.db pain_events, the principle ledger, the internalization chain).
|
|
4
|
+
* No new persisted state; the Ledger remains the only binding authority. */
|
|
1
5
|
export {};
|
package/console/dist/ui/api.d.ts
CHANGED
|
@@ -50,6 +50,34 @@ export declare function mutateRuleBinding(candidateId: string, body: RuleCandida
|
|
|
50
50
|
revisionStatus?: string;
|
|
51
51
|
nextAction?: string;
|
|
52
52
|
}>>;
|
|
53
|
+
/** PRI-1048: consume the REAL backend revision capability (revise-once route);
|
|
54
|
+
* eligibility was resolved server-side from the production resolver. */
|
|
55
|
+
export declare function reviseRuleBindingOnce(candidateId: string, body: {
|
|
56
|
+
expectedBindingRevision: number;
|
|
57
|
+
expectedScribeTaskId: string;
|
|
58
|
+
expectedTaskRevisionEpoch: number;
|
|
59
|
+
requestId: string;
|
|
60
|
+
}): Promise<ApiResponse<{
|
|
61
|
+
status: string;
|
|
62
|
+
reason?: string;
|
|
63
|
+
nextAction?: string;
|
|
64
|
+
}>>;
|
|
65
|
+
/** PRI-1048 R6 #4: the bounded one-shot SOURCE correction (PRI-1047) — the
|
|
66
|
+
* capability that applies when the binding revision budget is spent and the
|
|
67
|
+
* Artificer stopped for a source-material defect. CAS inputs come from the
|
|
68
|
+
* server-computed sourceCorrection preview; the server re-validates all of it. */
|
|
69
|
+
export declare function correctRuleSource(candidateId: string, body: {
|
|
70
|
+
expectedBindingRevision: number;
|
|
71
|
+
expectedScribeTaskId: string;
|
|
72
|
+
expectedArtificerTaskId: string;
|
|
73
|
+
expectedScribeArtifactDigest: string;
|
|
74
|
+
reason: string;
|
|
75
|
+
requestId: string;
|
|
76
|
+
}): Promise<ApiResponse<{
|
|
77
|
+
status: string;
|
|
78
|
+
reason?: string;
|
|
79
|
+
nextAction?: string;
|
|
80
|
+
}>>;
|
|
53
81
|
declare function fetchWorkspaces(): Promise<ApiResponse<WorkspaceEntryData[]>>;
|
|
54
82
|
declare function addWorkspace(name: string, path: string): Promise<ApiResponse<WorkspaceEntryData>>;
|
|
55
83
|
declare function removeWorkspace(name: string): Promise<ApiResponse<RemovedEnvelopeData>>;
|
package/console/dist/ui/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clearStoredToken, loadStoredToken, storeToken } from "./utils/token-storage.js";
|
|
2
|
-
import { validateBindingReview, validateBindingQueue, validateBindingMutation } from './utils/rule-binding-validators.js';
|
|
2
|
+
import { validateBindingReview, validateBindingQueue, validateBindingMutation, validateBindingRevise } from './utils/rule-binding-validators.js';
|
|
3
3
|
import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateRecoveryResult, validateFailedTaskDetail, validateOwnerDecisionsData, validateOwnerResolutionResult, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateUpdateRecovery, validateUpdateTransaction, validateApprovalRecordDirect, validatePrinciplesList, validateCorePrinciples, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateOwnerDecisionViewCore, validateOwnerDecisionInbox, validateOwnerDecisionLibrary, validateGovernanceExperienceSnapshot, validateRuleCodeOwnerReview, validateRuleCodeMutation, validateOwnerIdentityView, validateOwnerIdentityRegister, validateOwnerIdentityUnregister, } from "./utils/validators.js";
|
|
4
4
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
|
5
5
|
function getToken() {
|
|
@@ -136,6 +136,18 @@ export function fetchRuleBindingReview(candidateId, search = '') {
|
|
|
136
136
|
export function mutateRuleBinding(candidateId, body) {
|
|
137
137
|
return request(`/api/v1/governance/rule-candidate-bindings/${encodeURIComponent(candidateId)}`, { method: 'POST', body: JSON.stringify(body) }, validateBindingMutation);
|
|
138
138
|
}
|
|
139
|
+
/** PRI-1048: consume the REAL backend revision capability (revise-once route);
|
|
140
|
+
* eligibility was resolved server-side from the production resolver. */
|
|
141
|
+
export function reviseRuleBindingOnce(candidateId, body) {
|
|
142
|
+
return request(`/api/v1/governance/rule-candidate-bindings/${encodeURIComponent(candidateId)}/revise-once`, { method: 'POST', body: JSON.stringify(body) }, validateBindingRevise);
|
|
143
|
+
}
|
|
144
|
+
/** PRI-1048 R6 #4: the bounded one-shot SOURCE correction (PRI-1047) — the
|
|
145
|
+
* capability that applies when the binding revision budget is spent and the
|
|
146
|
+
* Artificer stopped for a source-material defect. CAS inputs come from the
|
|
147
|
+
* server-computed sourceCorrection preview; the server re-validates all of it. */
|
|
148
|
+
export function correctRuleSource(candidateId, body) {
|
|
149
|
+
return request(`/api/v1/governance/rule-candidate-bindings/${encodeURIComponent(candidateId)}/source-correct-once`, { method: 'POST', body: JSON.stringify(body) }, validateBindingRevise);
|
|
150
|
+
}
|
|
139
151
|
async function fetchWorkspaces() {
|
|
140
152
|
return request("/api/workspaces", undefined, validateWorkspaceList);
|
|
141
153
|
}
|