create-principles-disciple 1.121.10 → 1.122.0
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/console/dist/server/index.js +17 -0
- package/console/dist/server/models/OwnerDecisionConsoleModel.d.ts +39 -0
- package/console/dist/server/models/OwnerDecisionConsoleModel.js +233 -0
- package/console/dist/server/models/PrincipleClassifier.d.ts +3 -3
- package/console/dist/server/models/PrincipleClassifier.js +12 -5
- package/console/dist/server/models/PrinciplesConsoleModel.d.ts +1 -1
- package/console/dist/server/models/PrinciplesConsoleModel.js +2 -2
- package/console/dist/server/routes/failed-tasks.js +40 -2
- package/console/dist/server/routes/owner-decisions.d.ts +25 -0
- package/console/dist/server/routes/owner-decisions.js +186 -0
- package/console/dist/server/routes/principles.js +15 -7
- package/console/dist/ui/api.d.ts +12 -1
- package/console/dist/ui/api.js +9 -2
- package/console/dist/ui/components/notifications/NotificationProvider.js +8 -2
- package/console/dist/ui/i18n/en.json +33 -1
- package/console/dist/ui/i18n/zh-CN.json +33 -1
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +5 -1
- package/console/dist/ui/pages/focus/FocusPage.js +19 -2
- package/console/dist/ui/pages/focus/OwnerDecisionCard.d.ts +6 -0
- package/console/dist/ui/pages/focus/OwnerDecisionCard.js +86 -0
- package/console/dist/ui/pages/principles/PrinciplesPage.js +11 -5
- package/console/dist/ui/utils/validators.d.ts +37 -0
- package/console/dist/ui/utils/validators.js +123 -0
- package/console/dist/web/assets/app.css +11 -0
- package/console/dist/web/assets/app.js +2740 -2350
- package/core/dist/runtime-v2/__tests__/evaluator-repair-loop.test.js +20 -0
- package/core/dist/runtime-v2/__tests__/evaluator-repair-loop.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/rollout-reviewer-verdict-paths.test.js +26 -5
- package/core/dist/runtime-v2/__tests__/rollout-reviewer-verdict-paths.test.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +7 -1
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +4 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/evaluator-prompt-builder.test.js +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/internalization-transition-decision.test.js +15 -14
- package/core/dist/runtime-v2/internalization/__tests__/internalization-transition-decision.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.js +56 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js +883 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.js +328 -0
- package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/evaluator-output.d.ts +63 -2
- package/core/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-output.js +139 -2
- package/core/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +54 -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 +49 -2
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +34 -0
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +295 -12
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.js +10 -54
- package/core/dist/runtime-v2/internalization/internalization-orchestrator.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts +7 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.js +9 -2
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.js.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-resolution-service.d.ts +89 -0
- package/core/dist/runtime-v2/internalization/owner-resolution-service.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-resolution-service.js +272 -0
- package/core/dist/runtime-v2/internalization/owner-resolution-service.js.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-retry.d.ts +12 -0
- package/core/dist/runtime-v2/internalization/owner-retry.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-retry.js +23 -0
- package/core/dist/runtime-v2/internalization/owner-retry.js.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-review.d.ts +195 -0
- package/core/dist/runtime-v2/internalization/owner-review.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/owner-review.js +470 -0
- package/core/dist/runtime-v2/internalization/owner-review.js.map +1 -0
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +5 -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 +68 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.js +104 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/core/dist/runtime-v2/internalization/revision-reopen.d.ts +56 -0
- package/core/dist/runtime-v2/internalization/revision-reopen.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/revision-reopen.js +144 -0
- package/core/dist/runtime-v2/internalization/revision-reopen.js.map +1 -0
- package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts +12 -0
- package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js +145 -14
- package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js.map +1 -1
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.test.js +1 -0
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.test.js.map +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts +6 -0
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.js +9 -0
- package/core/dist/runtime-v2/store/runtime-state-manager.js.map +1 -1
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.d.ts +2 -0
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js +78 -0
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js.map +1 -0
- package/core/dist/runtime-v2/store/task/memory-task-store.d.ts +1 -0
- package/core/dist/runtime-v2/store/task/memory-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/memory-task-store.js +8 -0
- package/core/dist/runtime-v2/store/task/memory-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts +1 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js +52 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/task-store.d.ts +9 -0
- package/core/dist/runtime-v2/store/task/task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/workspace-isolation.test.js +1 -0
- package/core/dist/runtime-v2/store/workspace-isolation.test.js.map +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/runtime-internalization-retry.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-retry.js +14 -0
- package/pd-cli/dist/commands/runtime-internalization-retry.js.map +1 -1
- package/plugin/dist/bundle.js +580 -569
- package/plugin/dist/governance-audit.js +153 -153
- package/plugin/dist/rulehost-evidence.js +180 -180
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createRuntimeStateHandle, applyOwnerResolution, } from '@principles/core/runtime-v2';
|
|
2
|
+
import { OwnerDecisionConsoleModel } from '../models/OwnerDecisionConsoleModel.js';
|
|
3
|
+
import { sendSuccess, sendError, sendMethodNotAllowed, sendBadRequest } from '../utils/response.js';
|
|
4
|
+
import { readBody } from '../utils/request.js';
|
|
5
|
+
const models = new Map();
|
|
6
|
+
function getModel(workspaceDir) {
|
|
7
|
+
let model = models.get(workspaceDir);
|
|
8
|
+
if (!model) {
|
|
9
|
+
model = new OwnerDecisionConsoleModel(workspaceDir);
|
|
10
|
+
models.set(workspaceDir, model);
|
|
11
|
+
}
|
|
12
|
+
return model;
|
|
13
|
+
}
|
|
14
|
+
const RESOLVE_ACTIONS = new Set(['accept_current', 'revise_once', 'reject_current']);
|
|
15
|
+
/** rc-1/rc-2/rc-3: body 按未知值逐字段校验,非法即 400 fail-loud。 */
|
|
16
|
+
function parseResolveBody(raw) {
|
|
17
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
18
|
+
return { ok: false, error: 'Request body must be a JSON object.' };
|
|
19
|
+
}
|
|
20
|
+
const b = raw;
|
|
21
|
+
if (typeof b.action !== 'string' || !RESOLVE_ACTIONS.has(b.action)) {
|
|
22
|
+
return { ok: false, error: `action must be one of accept_current/revise_once/reject_current, got ${String(b.action)}` };
|
|
23
|
+
}
|
|
24
|
+
for (const field of ['reviewKey', 'expectedSourceRunId', 'expectedSourceArtifactId', 'expectedSourceArtifactHash']) {
|
|
25
|
+
const v = b[field];
|
|
26
|
+
if (typeof v !== 'string' || v.trim() === '') {
|
|
27
|
+
return { ok: false, error: `${field} must be a non-empty string.` };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (typeof b.expectedRevisionEpoch !== 'number' || !Number.isInteger(b.expectedRevisionEpoch) || b.expectedRevisionEpoch < 0) {
|
|
31
|
+
return { ok: false, error: 'expectedRevisionEpoch must be a non-negative integer.' };
|
|
32
|
+
}
|
|
33
|
+
if (b.ownerInstruction !== undefined && b.ownerInstruction !== null
|
|
34
|
+
&& (typeof b.ownerInstruction !== 'string' || b.ownerInstruction.length > 600)) {
|
|
35
|
+
return { ok: false, error: 'ownerInstruction must be a string of at most 600 characters (or null).' };
|
|
36
|
+
}
|
|
37
|
+
const { reviewKey } = b;
|
|
38
|
+
const { expectedSourceRunId } = b;
|
|
39
|
+
const { expectedSourceArtifactId } = b;
|
|
40
|
+
const { expectedSourceArtifactHash } = b;
|
|
41
|
+
if (typeof reviewKey !== 'string' || typeof expectedSourceRunId !== 'string'
|
|
42
|
+
|| typeof expectedSourceArtifactId !== 'string' || typeof expectedSourceArtifactHash !== 'string') {
|
|
43
|
+
return { ok: false, error: 'unreachable: string fields validated above' };
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
body: {
|
|
48
|
+
action: b.action,
|
|
49
|
+
reviewKey,
|
|
50
|
+
expectedRevisionEpoch: b.expectedRevisionEpoch,
|
|
51
|
+
expectedSourceRunId,
|
|
52
|
+
expectedSourceArtifactId,
|
|
53
|
+
expectedSourceArtifactHash,
|
|
54
|
+
...(typeof b.ownerInstruction === 'string' ? { ownerInstruction: b.ownerInstruction } : {}),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** OwnerResolutionOutcome → HTTP 响应映射(cli-6: 结构化 reason + nextAction)。 */
|
|
59
|
+
function sendOutcome(res, outcome) {
|
|
60
|
+
switch (outcome.status) {
|
|
61
|
+
case 'resolved':
|
|
62
|
+
sendSuccess(res, {
|
|
63
|
+
status: 'resolved',
|
|
64
|
+
resolutionId: outcome.resolutionId,
|
|
65
|
+
reviewKey: outcome.reviewKey,
|
|
66
|
+
action: outcome.action,
|
|
67
|
+
applied: outcome.applied,
|
|
68
|
+
...(outcome.effectiveDecision !== undefined ? { effectiveDecision: outcome.effectiveDecision } : {}),
|
|
69
|
+
...(outcome.targetTaskId !== undefined ? { targetTaskId: outcome.targetTaskId } : {}),
|
|
70
|
+
runnerWillApply: outcome.runnerWillApply,
|
|
71
|
+
nextAction: outcome.applied
|
|
72
|
+
? 'Resolution applied. Refresh the governance focus.'
|
|
73
|
+
: 'Resolution recorded durably; the pipeline runner will apply it without re-invoking the LLM. Refresh the governance focus.',
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
case 'not_found':
|
|
77
|
+
sendError(res, 404, 'task_not_found', 'Owner decision task not found.');
|
|
78
|
+
return;
|
|
79
|
+
case 'metadata_invalid':
|
|
80
|
+
sendError(res, 409, 'metadata_invalid', 'Task metadata failed PI hydration; refusing to resolve.', {
|
|
81
|
+
nextAction: 'Inspect the task metadata: pd runtime internalization integrity --json',
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
case 'not_decision_capable':
|
|
85
|
+
sendError(res, 409, 'not_decision_capable', 'This task is not currently decision-capable.', {
|
|
86
|
+
nextAction: 'Refresh the governance focus — the decision facts may have changed.',
|
|
87
|
+
blockers: outcome.blockers,
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
case 'stale_owner_decision':
|
|
91
|
+
sendError(res, 409, 'stale_owner_decision', 'The durable decision facts changed since this item was rendered. The decision was NOT applied.', {
|
|
92
|
+
nextAction: 'Refresh the governance focus and decide again on the current version.',
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
case 'already_resolved':
|
|
96
|
+
sendError(res, 409, 'already_resolved', `This decision was already resolved with action '${outcome.existingAction}'.`, {
|
|
97
|
+
nextAction: 'Refresh the governance focus.',
|
|
98
|
+
existingAction: outcome.existingAction,
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
case 'revise_target_unresolved':
|
|
102
|
+
sendError(res, 409, 'revise_target_unresolved', 'The revision target task could not be resolved from the lineage.', {
|
|
103
|
+
nextAction: 'Inspect the task lineage; this is a recovery-class failure.',
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
case 'revise_reopen_failed':
|
|
107
|
+
sendError(res, 409, 'revise_reopen_failed', `Reopening the revision target failed: ${outcome.reason}`, {
|
|
108
|
+
nextAction: 'Retry after the target task is no longer in flight, or inspect the task states.',
|
|
109
|
+
reason: outcome.reason,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
case 'cas_conflict':
|
|
113
|
+
sendError(res, 409, 'cas_conflict', 'Concurrent write detected while recording the resolution.', {
|
|
114
|
+
nextAction: 'Retry the request — the operation is idempotent.',
|
|
115
|
+
});
|
|
116
|
+
return;
|
|
117
|
+
default: {
|
|
118
|
+
// exhaustive guard
|
|
119
|
+
const exhaustive = outcome;
|
|
120
|
+
sendError(res, 500, 'owner_resolution_error', `Unhandled outcome: ${JSON.stringify(exhaustive)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function handleOwnerDecisionsRoute(req, res, ctx) {
|
|
125
|
+
const { workspaceDir, subPath, ownerIdentity } = ctx;
|
|
126
|
+
const method = req.method ?? 'GET';
|
|
127
|
+
// GET /api/v1/governance/owner-decisions — list
|
|
128
|
+
if (subPath === '' || subPath === '/') {
|
|
129
|
+
if (method !== 'GET') {
|
|
130
|
+
sendMethodNotAllowed(res);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const result = await getModel(workspaceDir).listOwnerDecisionItems();
|
|
135
|
+
sendSuccess(res, result);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
139
|
+
sendError(res, 500, 'owner_decisions_list_error', message, {
|
|
140
|
+
nextAction: 'Inspect the workspace state (.pd/state.db) and retry.',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// POST /api/v1/governance/owner-decisions/:taskId/resolve
|
|
146
|
+
const resolveMatch = /^\/([^/]+)\/resolve$/.exec(subPath);
|
|
147
|
+
if (resolveMatch) {
|
|
148
|
+
if (method !== 'POST') {
|
|
149
|
+
sendMethodNotAllowed(res);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- match group is always present
|
|
153
|
+
const taskId = decodeURIComponent(resolveMatch[1]);
|
|
154
|
+
let body;
|
|
155
|
+
try {
|
|
156
|
+
const raw = await readBody(req);
|
|
157
|
+
body = raw.trim() === '' ? {} : JSON.parse(raw);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
sendBadRequest(res, 'Request body must be valid JSON.');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const parsed = parseResolveBody(body);
|
|
164
|
+
if (!parsed.ok) {
|
|
165
|
+
sendBadRequest(res, parsed.error);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// 应用走 core 单一服务(writable RuntimeStateManager handle)
|
|
169
|
+
const handle = await createRuntimeStateHandle({ workspaceDir });
|
|
170
|
+
try {
|
|
171
|
+
const outcome = await applyOwnerResolution({ stateManager: handle.stateManager }, { taskId, request: parsed.body, identity: ownerIdentity });
|
|
172
|
+
sendOutcome(res, outcome);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
176
|
+
sendError(res, 500, 'owner_resolution_error', message, {
|
|
177
|
+
nextAction: 'Inspect the workspace state (.pd/state.db) and retry.',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await handle.close();
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
sendError(res, 404, 'not_found', `Route /api/v1/governance/owner-decisions${subPath} not found`);
|
|
186
|
+
}
|
|
@@ -42,7 +42,7 @@ async function getDecidedPrincipleIds(workspaceDir) {
|
|
|
42
42
|
// Runtime V2 uses <workspace>/.pd/state.db (NOT .state/state.db)
|
|
43
43
|
const dbPath = path.join(workspaceDir, '.pd', 'state.db');
|
|
44
44
|
if (!fs.existsSync(dbPath)) {
|
|
45
|
-
return { ids: new Set(), unavailableReason: 'approval_db_not_found' };
|
|
45
|
+
return { ids: new Set(), pendingIds: new Set(), unavailableReason: 'approval_db_not_found' };
|
|
46
46
|
}
|
|
47
47
|
let closeFn = null;
|
|
48
48
|
try {
|
|
@@ -51,25 +51,33 @@ async function getDecidedPrincipleIds(workspaceDir) {
|
|
|
51
51
|
closeFn = () => conn.close();
|
|
52
52
|
const db = conn.getDb();
|
|
53
53
|
// Join approvals with pi_artifacts to find decided principle IDs
|
|
54
|
-
|
|
54
|
+
// PRI-629: also resolve PENDING approvals — a pending approval is a real
|
|
55
|
+
// Owner decision (owner_actionable), unlike candidate lifecycle (in_pipeline).
|
|
56
|
+
const rows = db.prepare("SELECT DISTINCT a.source_principle_id, ap.status " +
|
|
55
57
|
"FROM approvals ap " +
|
|
56
58
|
"JOIN pi_artifacts a ON a.artifact_id = ap.artifact_id " +
|
|
57
|
-
"WHERE ap.status IN ('approved', 'rejected') " +
|
|
59
|
+
"WHERE ap.status IN ('approved', 'rejected', 'pending') " +
|
|
58
60
|
"AND a.source_principle_id IS NOT NULL").all();
|
|
59
61
|
// EP-01 Rule 1: treat DB rows as unknown; validate before use
|
|
60
62
|
// EP-01 Rule 2: no `as` cast — use getOwnStringField instead
|
|
61
63
|
const ids = new Set();
|
|
64
|
+
const pendingIds = new Set();
|
|
62
65
|
for (const row of rows) {
|
|
63
66
|
const val = getOwnStringField(row, 'source_principle_id');
|
|
64
|
-
if (val
|
|
67
|
+
if (val === undefined)
|
|
68
|
+
continue;
|
|
69
|
+
if (getOwnStringField(row, 'status') === 'pending') {
|
|
70
|
+
pendingIds.add(val);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
65
73
|
ids.add(val);
|
|
66
74
|
}
|
|
67
75
|
}
|
|
68
|
-
return { ids };
|
|
76
|
+
return { ids, pendingIds };
|
|
69
77
|
}
|
|
70
78
|
catch (err) {
|
|
71
79
|
const message = err instanceof Error ? err.message : String(err);
|
|
72
|
-
return { ids: new Set(), unavailableReason: `approval_query_failed: ${message}` };
|
|
80
|
+
return { ids: new Set(), pendingIds: new Set(), unavailableReason: `approval_query_failed: ${message}` };
|
|
73
81
|
}
|
|
74
82
|
finally {
|
|
75
83
|
closeFn?.();
|
|
@@ -197,7 +205,7 @@ export async function handlePrinciplesRoute({ req, res, workspaceDir, subPath, f
|
|
|
197
205
|
const VALID_FILTERS = new Set(['all', 'actionable']);
|
|
198
206
|
const filter = (filterRaw !== null && VALID_FILTERS.has(filterRaw) ? filterRaw : 'actionable');
|
|
199
207
|
const decidedResult = await getDecidedPrincipleIds(workspaceDir);
|
|
200
|
-
const result = await model.listPrinciples(filter, decidedResult.ids);
|
|
208
|
+
const result = await model.listPrinciples(filter, decidedResult.ids, decidedResult.pendingIds);
|
|
201
209
|
// Surface approval cross-check unavailability to the UI (ERR-002)
|
|
202
210
|
if (decidedResult.unavailableReason) {
|
|
203
211
|
result.approvalCrossCheckUnavailable = decidedResult.unavailableReason;
|
package/console/dist/ui/api.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ApiResponse } from "../types.js";
|
|
2
|
+
import type { OwnerDecisionsData, OwnerResolutionResultData } from "./utils/validators.js";
|
|
2
3
|
import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm } from "./utils/signal-keywords-api.js";
|
|
3
4
|
import type { GovernanceExperienceSnapshot, OwnerGovernanceView } from '@principles/core/runtime-v2';
|
|
4
5
|
import type { OwnerIdentityViewData, OwnerIdentityRegisterData, OwnerIdentityUnregisterData } from "./utils/validators.js";
|
|
@@ -148,6 +149,16 @@ declare function updateOutputLanguage(outputLanguage: string): Promise<ApiRespon
|
|
|
148
149
|
declare function fetchGovernanceQueue(): Promise<ApiResponse<GovernanceQueueData>>;
|
|
149
150
|
declare function fetchGovernanceExperience(): Promise<ApiResponse<GovernanceExperienceSnapshot>>;
|
|
150
151
|
declare function recoverFailedTask(taskId: string, reason?: string, force?: boolean): Promise<ApiResponse<RecoveryResultData>>;
|
|
152
|
+
declare function fetchOwnerDecisions(): Promise<ApiResponse<OwnerDecisionsData>>;
|
|
153
|
+
declare function resolveOwnerDecision(taskId: string, body: {
|
|
154
|
+
action: 'accept_current' | 'revise_once' | 'reject_current';
|
|
155
|
+
reviewKey: string;
|
|
156
|
+
expectedRevisionEpoch: number;
|
|
157
|
+
expectedSourceRunId: string;
|
|
158
|
+
expectedSourceArtifactId: string;
|
|
159
|
+
expectedSourceArtifactHash: string;
|
|
160
|
+
ownerInstruction?: string | null;
|
|
161
|
+
}): Promise<ApiResponse<OwnerResolutionResultData>>;
|
|
151
162
|
declare function fetchApprovalsGrouped(): Promise<ApiResponse<ApprovalsGroupedData>>;
|
|
152
163
|
declare function fetchAllActivations(): Promise<ApiResponse<ActivationsData>>;
|
|
153
164
|
declare function disableActivation(activationId: string): Promise<ApiResponse<DisableActivationData>>;
|
|
@@ -214,7 +225,7 @@ export interface FollowUpPayload {
|
|
|
214
225
|
candidateId?: string;
|
|
215
226
|
}
|
|
216
227
|
declare function dispatchFollowUp(decisionId: string, payload: FollowUpPayload): Promise<ApiResponse<FollowUpResponseData>>;
|
|
217
|
-
export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
228
|
+
export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchOwnerDecisions, resolveOwnerDecision, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
218
229
|
export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, ActivationsData, DisableActivationData, RuleCodeOwnerReviewData, RuleCodeMutationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
|
|
219
230
|
export type { SignalKeyword, PendingSignalTerm } from "./utils/signal-keywords-types.js";
|
|
220
231
|
export type { ActivationRecordData as ActivationRecord } from "./utils/validators.js";
|
package/console/dist/ui/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, } from "./utils/signal-keywords-api.js";
|
|
2
|
-
import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateRecoveryResult, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateGovernanceExperienceSnapshot, validateRuleCodeOwnerReview, validateRuleCodeMutation, validateOwnerIdentityView, validateOwnerIdentityRegister, validateOwnerIdentityUnregister, } from "./utils/validators.js";
|
|
2
|
+
import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateRecoveryResult, validateOwnerDecisionsData, validateOwnerResolutionResult, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateGovernanceExperienceSnapshot, validateRuleCodeOwnerReview, validateRuleCodeMutation, validateOwnerIdentityView, validateOwnerIdentityRegister, validateOwnerIdentityUnregister, } from "./utils/validators.js";
|
|
3
3
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
|
4
4
|
function getToken() {
|
|
5
5
|
return sessionStorage.getItem("pd_token");
|
|
@@ -454,6 +454,13 @@ async function recoverFailedTask(taskId, reason, force) {
|
|
|
454
454
|
body: JSON.stringify(body),
|
|
455
455
|
}, validateRecoveryResult);
|
|
456
456
|
}
|
|
457
|
+
// PRI-629: unified Owner Decision inbox — read projection + resolution.
|
|
458
|
+
async function fetchOwnerDecisions() {
|
|
459
|
+
return request('/api/v1/governance/owner-decisions', undefined, validateOwnerDecisionsData);
|
|
460
|
+
}
|
|
461
|
+
async function resolveOwnerDecision(taskId, body) {
|
|
462
|
+
return request('/api/v1/governance/owner-decisions/' + encodeURIComponent(taskId) + '/resolve', { method: 'POST', body: JSON.stringify(body) }, validateOwnerResolutionResult);
|
|
463
|
+
}
|
|
457
464
|
async function fetchApprovalsGrouped() {
|
|
458
465
|
return request('/api/v1/approvals/grouped', undefined, validateApprovalsGrouped);
|
|
459
466
|
}
|
|
@@ -570,4 +577,4 @@ listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendin
|
|
|
570
577
|
// auth
|
|
571
578
|
getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport,
|
|
572
579
|
// Feedback submit ladder (Slice 3, spec §8)
|
|
573
|
-
fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
580
|
+
fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchOwnerDecisions, resolveOwnerDecision, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useCallback, useEffect, useRef, useState, } from 'react';
|
|
3
|
-
import { fetchGovernanceQueue } from '../../api.js';
|
|
3
|
+
import { fetchGovernanceQueue, fetchOwnerDecisions } from '../../api.js';
|
|
4
4
|
import { useNotificationSound } from '../../hooks/useNotificationSound.js';
|
|
5
5
|
import { diffNotificationCounts } from './notification-reducer.js';
|
|
6
6
|
import { loadSoundEnabled, saveSoundEnabled } from './sound-storage.js';
|
|
@@ -33,8 +33,14 @@ export function NotificationProvider({ children }) {
|
|
|
33
33
|
console.warn('Notification poll failed:', result.error);
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
const pendingCount = result.data.pendingReviewCount;
|
|
37
36
|
const degradedCount = result.data.degradedSignals?.length ?? 0;
|
|
37
|
+
// PRI-629 (SPEC §27): 侧边栏徽标 N = 真实可执行 Owner 决策数
|
|
38
|
+
// (OwnerDecisionItem.length) — 不是 approvals pending / candidate /
|
|
39
|
+
// needs_human_review 计数。投影失败时回退 approvals pending (保守)。
|
|
40
|
+
const decisionsResult = await fetchOwnerDecisions();
|
|
41
|
+
const pendingCount = decisionsResult.success
|
|
42
|
+
? decisionsResult.data.total
|
|
43
|
+
: result.data.pendingReviewCount;
|
|
38
44
|
hasSuccessfulPollRef.current = true;
|
|
39
45
|
setState((prev) => ({
|
|
40
46
|
...prev,
|
|
@@ -260,7 +260,36 @@
|
|
|
260
260
|
},
|
|
261
261
|
"zeroStateHealthy": "No items need your judgment right now. PD has checked behavior evidence, principle review queue, and system signals.",
|
|
262
262
|
"zeroStateDbMissing": "PD has not run in this workspace yet. Once the state database is initialized, governance data will appear here.",
|
|
263
|
-
"evidenceInProgress": "{{count}} behavior evidence item(s) recorded, being diagnosed and processed."
|
|
263
|
+
"evidenceInProgress": "{{count}} behavior evidence item(s) recorded, being diagnosed and processed.",
|
|
264
|
+
"ownerDecision": {
|
|
265
|
+
"sectionTitle": "Needs your decision",
|
|
266
|
+
"empty": "Nothing needs your decision right now. Problems the machine can solve on its own will not disturb you.",
|
|
267
|
+
"unavailable": "(unavailable)",
|
|
268
|
+
"loadError": "The decision list is temporarily unavailable — the governance summary is still shown.",
|
|
269
|
+
"kindEvaluator": "Evaluator review",
|
|
270
|
+
"kindRollout": "Rollout review",
|
|
271
|
+
"kindApproval": "Deployment approval",
|
|
272
|
+
"kindRulecode": "RuleCode decision",
|
|
273
|
+
"legacyBadge": "Inferred from history",
|
|
274
|
+
"machineRecommendationLabel": "Machine recommendation",
|
|
275
|
+
"rolloutSafetyNote": "Accept this review and continue. High-risk rules still require an independent deployment approval.",
|
|
276
|
+
"acceptCurrent": "Accept current version",
|
|
277
|
+
"reviseOnce": "Revise once more",
|
|
278
|
+
"rejectCurrent": "Reject",
|
|
279
|
+
"instructionLabel": "Revision guidance (optional, one sentence)",
|
|
280
|
+
"instructionPlaceholder": "e.g. Do not add new tool-naming requirements; only address the unresolved items from the last round.",
|
|
281
|
+
"instructionRequired": "Fill in the revision guidance, or collapse the input and submit directly.",
|
|
282
|
+
"actionConsequence": "Accept = continue with the current version (the machine verdict is preserved permanently); Revise once = authorize one extra revision round (automatic budget unchanged); Reject = terminate this evolution.",
|
|
283
|
+
"advanced": "Advanced diagnostics",
|
|
284
|
+
"resolved": "Resolution recorded.",
|
|
285
|
+
"staleError": "The facts of this item changed (a new evaluation may exist). Your decision was NOT applied — refresh and decide again.",
|
|
286
|
+
"alreadyResolved": "This decision was already handled; no repeat action needed.",
|
|
287
|
+
"actionFailed": "Action failed, please retry later.",
|
|
288
|
+
"approvalHint": "The deployment approval for this principle is still waiting in the approval queue.",
|
|
289
|
+
"rulecodeHint": "This rule is in shadow activation and needs a decision in activation management.",
|
|
290
|
+
"goApprovalsCta": "Go to deployment approvals",
|
|
291
|
+
"goActivationCta": "Go to activation management"
|
|
292
|
+
}
|
|
264
293
|
},
|
|
265
294
|
"pain": {
|
|
266
295
|
"eyebrow": "Behavior Evidence",
|
|
@@ -477,6 +506,7 @@
|
|
|
477
506
|
"statusApproved": "Approved",
|
|
478
507
|
"statusRejected": "Rejected",
|
|
479
508
|
"statusParked": "Parked",
|
|
509
|
+
"statusCandidate": "Internalizing",
|
|
480
510
|
"emptyTitle": "No principles to review",
|
|
481
511
|
"emptyDescription": "When PD captures behavior deviation signals, principle candidates will appear here for your review.",
|
|
482
512
|
"emptyActionable": "No owner-actionable principles at this time. When PD captures behavior deviation signals, principle candidates will appear here for your review. You can check the Behavior Evidence page to see if PD is actively collecting signals.",
|
|
@@ -1576,6 +1606,8 @@
|
|
|
1576
1606
|
"recoverConfirmButton": "Recover",
|
|
1577
1607
|
"recoverSuccess": "Recovery accepted — the task is pending again",
|
|
1578
1608
|
"recoverFailed": "Recovery failed",
|
|
1609
|
+
"awaitingOwnerDecision": "Awaiting owner decision",
|
|
1610
|
+
"goGovernanceFocus": "Go to governance focus",
|
|
1579
1611
|
"taskId": "Task ID",
|
|
1580
1612
|
"painId": "Pain ID",
|
|
1581
1613
|
"kind": "Kind",
|
|
@@ -260,7 +260,36 @@
|
|
|
260
260
|
},
|
|
261
261
|
"zeroStateHealthy": "当前没有需要你判断的事项。PD 已检查行为证据、原则审查队列和系统信号。",
|
|
262
262
|
"zeroStateDbMissing": "PD 尚未在此工作空间中运行。状态数据库初始化后,治理数据将在这里呈现。",
|
|
263
|
-
"evidenceInProgress": "{{count}} 条行为证据已记录,正在诊断和处理中。"
|
|
263
|
+
"evidenceInProgress": "{{count}} 条行为证据已记录,正在诊断和处理中。",
|
|
264
|
+
"ownerDecision": {
|
|
265
|
+
"sectionTitle": "需要你决定",
|
|
266
|
+
"empty": "现在没有需要你决定的事项。机器能自己解决的问题不会打扰你。",
|
|
267
|
+
"unavailable": "(暂不可用)",
|
|
268
|
+
"loadError": "决策列表暂时不可用——治理摘要仍可查看。",
|
|
269
|
+
"kindEvaluator": "Evaluator 评审",
|
|
270
|
+
"kindRollout": "Rollout 评审",
|
|
271
|
+
"kindApproval": "部署审批",
|
|
272
|
+
"kindRulecode": "RuleCode 决策",
|
|
273
|
+
"legacyBadge": "历史数据推断",
|
|
274
|
+
"machineRecommendationLabel": "机器建议",
|
|
275
|
+
"rolloutSafetyNote": "接受当前评审并继续。高风险规则仍需经过独立部署审批。",
|
|
276
|
+
"acceptCurrent": "接受当前版本",
|
|
277
|
+
"reviseOnce": "再修改一次",
|
|
278
|
+
"rejectCurrent": "拒绝",
|
|
279
|
+
"instructionLabel": "修订指导(可选,一句话)",
|
|
280
|
+
"instructionPlaceholder": "例如:不要增加新的工具命名要求,只处理上一轮未解决问题。",
|
|
281
|
+
"instructionRequired": "请填写修订指导,或收起输入后直接提交。",
|
|
282
|
+
"actionConsequence": "接受 = 按当前版本继续(机器原判定永久保留);再修改一次 = 授权额外一轮修订(自动预算不变);拒绝 = 终止本条演化。",
|
|
283
|
+
"advanced": "高级诊断",
|
|
284
|
+
"resolved": "裁决已记录。",
|
|
285
|
+
"staleError": "该事项的事实已变化(可能有新的评估结果)。未执行你的决定,请刷新后重新裁决。",
|
|
286
|
+
"alreadyResolved": "该决策已被处理过,无需重复操作。",
|
|
287
|
+
"actionFailed": "操作失败,请稍后重试。",
|
|
288
|
+
"approvalHint": "该原则的部署审批仍在审批队列中等待处理。",
|
|
289
|
+
"rulecodeHint": "该规则处于影子激活期,需要在激活管理中裁决。",
|
|
290
|
+
"goApprovalsCta": "前往部署审批",
|
|
291
|
+
"goActivationCta": "前往激活管理"
|
|
292
|
+
}
|
|
264
293
|
},
|
|
265
294
|
"pain": {
|
|
266
295
|
"eyebrow": "行为证据",
|
|
@@ -477,6 +506,7 @@
|
|
|
477
506
|
"statusApproved": "已批准",
|
|
478
507
|
"statusRejected": "已拒绝",
|
|
479
508
|
"statusParked": "已暂存",
|
|
509
|
+
"statusCandidate": "内化中",
|
|
480
510
|
"emptyTitle": "还没有可审查原则",
|
|
481
511
|
"emptyDescription": "当 PD 捕获到行为偏差信号时,会在这里生成原则候选,等待你审查。",
|
|
482
512
|
"emptyActionable": "当前没有待决策的原则。当 PD 捕获到行为偏差信号时,原则候选会出现在这里。你可以前往行为证据页查看 PD 是否正在收集信号。",
|
|
@@ -1576,6 +1606,8 @@
|
|
|
1576
1606
|
"recoverConfirmButton": "恢复",
|
|
1577
1607
|
"recoverSuccess": "恢复已接受——任务已重新进入待处理状态",
|
|
1578
1608
|
"recoverFailed": "恢复失败",
|
|
1609
|
+
"awaitingOwnerDecision": "等待拥有者决策",
|
|
1610
|
+
"goGovernanceFocus": "前往治理焦点",
|
|
1579
1611
|
"taskId": "任务 ID",
|
|
1580
1612
|
"painId": "Pain ID",
|
|
1581
1613
|
"kind": "类型",
|
|
@@ -88,6 +88,9 @@ function validateTask(v) {
|
|
|
88
88
|
const painId = readNullableString(v, "painId");
|
|
89
89
|
const lastError = readNullableString(v, "lastError");
|
|
90
90
|
const lastAttemptAt = readNullableString(v, "lastAttemptAt");
|
|
91
|
+
const ownerDecisionRequired = Object.hasOwn(v, "ownerDecisionRequired")
|
|
92
|
+
? v.ownerDecisionRequired === true
|
|
93
|
+
: undefined;
|
|
91
94
|
return {
|
|
92
95
|
taskId,
|
|
93
96
|
taskKind,
|
|
@@ -98,6 +101,7 @@ function validateTask(v) {
|
|
|
98
101
|
maxAttempts,
|
|
99
102
|
createdAt,
|
|
100
103
|
lastAttemptAt,
|
|
104
|
+
...(ownerDecisionRequired !== undefined ? { ownerDecisionRequired } : {}),
|
|
101
105
|
};
|
|
102
106
|
}
|
|
103
107
|
function validateFailedTasksData(v) {
|
|
@@ -318,5 +322,5 @@ function LoadedContent({ data, onCreateDraft, onRecover, t }) {
|
|
|
318
322
|
.replace("{total}", String(data.total)) }))] })] }));
|
|
319
323
|
}
|
|
320
324
|
function TaskTable({ tasks, onCreateDraft, onRecover, t }) {
|
|
321
|
-
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 pb-2 border-b border-line font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: [_jsx("span", { children: t("pages.failedTasks.taskId") }), _jsx("span", { children: t("pages.failedTasks.painId") }), _jsx("span", { children: t("pages.failedTasks.status") }), _jsx("span", { children: t("pages.failedTasks.lastError") }), _jsx("span", { children: t("pages.failedTasks.attempts") }), _jsx("span", { children: t("pages.failedTasks.lastAttempt") }), _jsx("span", { "aria-hidden": "true" })] }), tasks.map((task) => (_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 py-2 items-center text-[13px] border-b border-line/50 last:border-b-0", children: [_jsx("span", { className: "font-mono text-ink-2 truncate", title: task.taskId, children: truncateId(task.taskId) }), _jsx("span", { className: "font-mono text-ink-3 truncate", title: task.painId ?? "", children: task.painId ? truncateId(task.painId) : t("pages.failedTasks.noPainId") }), _jsx(Badge, { variant: statusToVariant(task.status), children: task.status }), _jsx("span", { className: "text-ink-3 truncate", title: task.lastError ?? "", children: task.lastError ?? "—" }), _jsx("span", { className: "font-mono text-ink-2 text-center", children: task.attemptCount }), _jsx("span", { className: "font-mono text-ink-3 text-[12px]", children: task.lastAttemptAt ? formatDate(task.lastAttemptAt) : "—" }), onRecover
|
|
325
|
+
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 pb-2 border-b border-line font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: [_jsx("span", { children: t("pages.failedTasks.taskId") }), _jsx("span", { children: t("pages.failedTasks.painId") }), _jsx("span", { children: t("pages.failedTasks.status") }), _jsx("span", { children: t("pages.failedTasks.lastError") }), _jsx("span", { children: t("pages.failedTasks.attempts") }), _jsx("span", { children: t("pages.failedTasks.lastAttempt") }), _jsx("span", { "aria-hidden": "true" })] }), tasks.map((task) => (_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 py-2 items-center text-[13px] border-b border-line/50 last:border-b-0", children: [_jsx("span", { className: "font-mono text-ink-2 truncate", title: task.taskId, children: truncateId(task.taskId) }), _jsx("span", { className: "font-mono text-ink-3 truncate", title: task.painId ?? "", children: task.painId ? truncateId(task.painId) : t("pages.failedTasks.noPainId") }), _jsx(Badge, { variant: statusToVariant(task.status), children: task.status }), _jsx("span", { className: "text-ink-3 truncate", title: task.lastError ?? "", children: task.lastError ?? "—" }), _jsx("span", { className: "font-mono text-ink-2 text-center", children: task.attemptCount }), _jsx("span", { className: "font-mono text-ink-3 text-[12px]", children: task.lastAttemptAt ? formatDate(task.lastAttemptAt) : "—" }), task.ownerDecisionRequired === true ? (_jsxs("span", { className: "whitespace-nowrap text-[12px]", children: [_jsx("span", { className: "text-amber", children: t("pages.failedTasks.awaitingOwnerDecision") }), " ", _jsx("a", { href: "#/focus", className: "text-gov underline underline-offset-2 hover:text-gov/80", "data-testid": `go-focus-${task.taskId}`, children: t("pages.failedTasks.goGovernanceFocus") })] })) : onRecover ? (_jsx(Button, { variant: "default", size: "sm", onClick: () => onRecover(task), className: "whitespace-nowrap", children: t("pages.failedTasks.recover") })) : null, _jsx(Button, { variant: "outline", size: "sm", onClick: () => onCreateDraft(task), className: "whitespace-nowrap", children: t("pages.failedTasks.createDraft") })] }, task.taskId)))] }));
|
|
322
326
|
}
|
|
@@ -8,7 +8,8 @@ import { PageLoading } from "../../components/layout/page-loading.js";
|
|
|
8
8
|
import { SectionTitle } from "../../components/layout/section-title.js";
|
|
9
9
|
import { DailyThoughtCard } from "../../components/focus/daily-thought-card.js";
|
|
10
10
|
import { ShinyText } from "../../components/ui/shiny-text.js";
|
|
11
|
-
import { fetchGovernanceQueue, fetchApprovalsGrouped, approveApproval, rejectApproval, editApproval, fetchAllActivations, } from "../../api.js";
|
|
11
|
+
import { fetchGovernanceQueue, fetchApprovalsGrouped, approveApproval, rejectApproval, editApproval, fetchAllActivations, fetchOwnerDecisions, } from "../../api.js";
|
|
12
|
+
import { OwnerDecisionCard } from "./OwnerDecisionCard.js";
|
|
12
13
|
import { fetchGovernanceExperience } from "../../api.js";
|
|
13
14
|
export function summarizeDecisionResults(results) {
|
|
14
15
|
const failures = results.filter((result) => !result.success);
|
|
@@ -458,6 +459,9 @@ export function FocusPage({ featureFlags }) {
|
|
|
458
459
|
const [groupedErrorReason, setGroupedErrorReason] = useState(null);
|
|
459
460
|
const [ruleCodeItems, setRuleCodeItems] = useState([]);
|
|
460
461
|
const [ruleCodeErrorReason, setRuleCodeErrorReason] = useState(null);
|
|
462
|
+
// PRI-629: 统一 Owner Inbox — 两种模式都加载 (决策与治理摘要模式正交)
|
|
463
|
+
const [ownerDecisionItems, setOwnerDecisionItems] = useState([]);
|
|
464
|
+
const [ownerDecisionError, setOwnerDecisionError] = useState(null);
|
|
461
465
|
const loadData = useCallback(async () => {
|
|
462
466
|
setLoadingState("loading");
|
|
463
467
|
setErrorMessage(null);
|
|
@@ -507,6 +511,17 @@ export function FocusPage({ featureFlags }) {
|
|
|
507
511
|
setRuleCodeItems([]);
|
|
508
512
|
setRuleCodeErrorReason(activationsResult.error);
|
|
509
513
|
}
|
|
514
|
+
// PRI-629: 统一 Owner Inbox (decision-capable NHR + approvals + rulecode)。
|
|
515
|
+
// 投影失败不阻塞页面 (rc-9 降级 — 显示原因,治理摘要仍可用)。
|
|
516
|
+
const decisionsResult = await fetchOwnerDecisions();
|
|
517
|
+
if (decisionsResult.success) {
|
|
518
|
+
setOwnerDecisionItems(decisionsResult.data.items);
|
|
519
|
+
setOwnerDecisionError(null);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
setOwnerDecisionItems([]);
|
|
523
|
+
setOwnerDecisionError(decisionsResult.error ?? "Owner decisions unavailable");
|
|
524
|
+
}
|
|
510
525
|
setLoadingState("loaded");
|
|
511
526
|
}, [experienceMode, t]);
|
|
512
527
|
useEffect(() => {
|
|
@@ -551,7 +566,9 @@ export function FocusPage({ featureFlags }) {
|
|
|
551
566
|
? "bg-amber/10 text-amber border border-amber/20"
|
|
552
567
|
: governanceState === "in_progress"
|
|
553
568
|
? "bg-green/10 text-green border border-green/20"
|
|
554
|
-
: "text-ink-4 border border-line bg-surface/80"}`, role: "status", children: t(`pages.focus.stateLabel.${governanceState}`) }) }), _jsx("div", { className: "text-ink-2 text-[13px] leading-relaxed mt-1", children: stateReason }), _jsxs("div", { className: "text-ink-4 text-[13px] leading-relaxed mt-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.nextActionLabel") }), " ", nextAction] })] })) : null,
|
|
569
|
+
: "text-ink-4 border border-line bg-surface/80"}`, role: "status", children: t(`pages.focus.stateLabel.${governanceState}`) }) }), _jsx("div", { className: "text-ink-2 text-[13px] leading-relaxed mt-1", children: stateReason }), _jsxs("div", { className: "text-ink-4 text-[13px] leading-relaxed mt-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.nextActionLabel") }), " ", nextAction] })] })) : null, _jsxs("section", { "aria-label": t("pages.focus.ownerDecision.sectionTitle"), className: "mb-7", "data-testid": "owner-decisions-section", children: [_jsxs("div", { className: "flex items-baseline gap-2 mb-3", children: [_jsx(SectionTitle, { children: t("pages.focus.ownerDecision.sectionTitle") }), _jsx("span", { className: "font-mono text-ink-4 text-[12px]", children: ownerDecisionError !== null
|
|
570
|
+
? t("pages.focus.ownerDecision.unavailable")
|
|
571
|
+
: `· ${ownerDecisionItems.length}` })] }), ownerDecisionError !== null && (_jsx("p", { className: "text-ink-4 text-[12.5px]", children: t("pages.focus.ownerDecision.loadError") })), ownerDecisionError === null && ownerDecisionItems.length === 0 && (_jsx("p", { className: "text-ink-4 text-[13px]", children: t("pages.focus.ownerDecision.empty") })), ownerDecisionItems.map((item) => (_jsx(OwnerDecisionCard, { item: item, onResolved: () => { void loadData(); } }, item.reviewKey)))] }), !experienceMode && (_jsxs(_Fragment, { children: [_jsx(ProseSummary, { pendingCount: pendingCount, deviationCount: deviationCount, stagnationCount: stagnationCount, evidenceCount: evidenceCount }), _jsx(FeedbackStratification, { gateBlocksToday: gateBlocksToday, inProgressCount: evidenceCount, pendingCount: pendingCount }), !experienceMode && governanceState === "none" && pendingCount === 0 && deviationCount === 0 && stagnationCount === 0 && (stateReasonCode === "state_db_missing" ? (_jsx(ZeroStateDbMissing, {})) : (_jsxs(_Fragment, { children: [_jsx(ZeroStateHealthy, {}), _jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })] }))), governanceState === "in_progress" && inProgressSummary && (_jsx(InProgressGuide, { summary: inProgressSummary })), degradedSignals && degradedSignals.length > 0 && (_jsx(DegradedSummary, { signals: degradedSignals }))] })), _jsx(DailyThoughtCard, {}), experienceMode && experienceData !== null && experienceData.summary.primaryAttention === "all_clear" && pendingGroups.length === 0 && (_jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })), (ruleCodeErrorReason || ruleCodePending.length > 0 || ruleCodeAlerts.length > 0) && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-rulecode-owner", children: [_jsx(SectionTitle, { id: "section-rulecode-owner", children: t("pages.focus.ruleCodeOwnerQueue") }), ruleCodeErrorReason && (_jsxs("div", { className: "mb-3 rounded border border-amber/30 bg-panel p-4 text-[12px] text-ink-3", children: [_jsx("div", { className: "font-medium text-amber", children: t("pages.focus.ruleCodeUnavailable") }), _jsx("div", { className: "mt-1 font-mono", children: ruleCodeErrorReason }), _jsx("div", { className: "mt-1", children: t("pages.focus.ruleCodeUnavailableNextAction") })] })), _jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [ruleCodePending.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-gov/30 bg-panel p-4 hover:border-gov", children: [_jsx("div", { className: "font-medium text-ink", children: t("pages.focus.ruleCodePending") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodePendingCount", { count: ruleCodePending.length }) })] })), ruleCodeAlerts.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-danger/30 bg-panel p-4 hover:border-danger", children: [_jsx("div", { className: "font-medium text-danger", children: t("pages.focus.ruleCodeAlerts") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodeAlertCount", { count: ruleCodeAlerts.length }) })] }))] })] })), _jsxs("section", { id: "approval-queue-section", className: "mt-8", "aria-labelledby": "section-pending", children: [_jsx(SectionTitle, { id: "section-pending", children: t("pages.focus.sectionPending") }), pendingGroups.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: pendingGroups.map((group) => (_jsx(PendingReviewCard, { group: group, onDecisionApplied: loadData }, group.principleId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: approvalDataUnavailable
|
|
555
572
|
? (groupedErrorReason
|
|
556
573
|
? `${t("pages.focus.loadError")} (${groupedErrorReason})`
|
|
557
574
|
: t("pages.focus.loadError"))
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OwnerDecisionItemData } from "../../utils/validators.js";
|
|
2
|
+
export interface OwnerDecisionCardProps {
|
|
3
|
+
item: OwnerDecisionItemData;
|
|
4
|
+
onResolved: () => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function OwnerDecisionCard({ item, onResolved }: OwnerDecisionCardProps): import("react").JSX.Element;
|