create-principles-disciple 1.145.21 → 1.145.22
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 +2 -2
- package/console/dist/server/index.js +11 -0
- package/console/dist/server/models/ApprovalsConsoleModel.js +10 -11
- package/console/dist/server/models/RuleCandidateBindingConsoleModel.d.ts +40 -0
- package/console/dist/server/models/RuleCandidateBindingConsoleModel.js +130 -0
- package/console/dist/server/models/artifact-principle-resolver.d.ts +2 -2
- package/console/dist/server/models/artifact-principle-resolver.js +10 -1
- package/console/dist/server/models/principle-id-resolution.d.ts +7 -12
- package/console/dist/server/models/principle-id-resolution.js +7 -94
- package/console/dist/server/routes/rule-candidate-bindings.d.ts +10 -0
- package/console/dist/server/routes/rule-candidate-bindings.js +116 -0
- package/console/dist/shared/rule-candidate-binding-contract.d.ts +30 -0
- package/console/dist/shared/rule-candidate-binding-contract.js +1 -0
- package/console/dist/ui/api.d.ts +9 -0
- package/console/dist/ui/api.js +10 -0
- package/console/dist/ui/i18n/en.json +25 -0
- package/console/dist/ui/i18n/zh-CN.json +25 -0
- package/console/dist/ui/pages/focus/FocusPage.js +2 -1
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +2 -0
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +68 -0
- package/console/dist/ui/utils/rule-binding-validators.d.ts +8 -0
- package/console/dist/ui/utils/rule-binding-validators.js +46 -0
- package/console/dist/web/assets/app.css +6 -0
- package/console/dist/web/assets/app.js +30 -30
- package/core/dist/principle-tree-ledger.d.ts +24 -4
- package/core/dist/principle-tree-ledger.d.ts.map +1 -1
- package/core/dist/principle-tree-ledger.js +201 -24
- package/core/dist/principle-tree-ledger.js.map +1 -1
- package/core/dist/runtime-v2/activation/ledger-identity.d.ts +4 -22
- package/core/dist/runtime-v2/activation/ledger-identity.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/ledger-identity.js +54 -0
- package/core/dist/runtime-v2/activation/ledger-identity.js.map +1 -1
- package/core/dist/runtime-v2/adapter/principle-tree-ledger-adapter.d.ts +11 -0
- package/core/dist/runtime-v2/adapter/principle-tree-ledger-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/principle-tree-ledger-adapter.js +67 -1
- package/core/dist/runtime-v2/adapter/principle-tree-ledger-adapter.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +2 -0
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +1 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts +3 -0
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.js +15 -2
- package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/candidate-identity.d.ts +17 -0
- package/core/dist/runtime-v2/internalization/candidate-identity.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/candidate-identity.js +56 -0
- package/core/dist/runtime-v2/internalization/candidate-identity.js.map +1 -0
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +43 -2
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +4 -0
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.js +13 -0
- package/core/dist/runtime-v2/internalization/peer-runner-contracts.js.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.js +8 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-binding-revision.d.ts +28 -0
- package/core/dist/runtime-v2/internalization/rule-binding-revision.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/rule-binding-revision.js +92 -0
- package/core/dist/runtime-v2/internalization/rule-binding-revision.js.map +1 -0
- package/core/dist/runtime-v2/internalization/scribe-runner.d.ts +7 -1
- package/core/dist/runtime-v2/internalization/scribe-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-runner.js +67 -3
- package/core/dist/runtime-v2/internalization/scribe-runner.js.map +1 -1
- package/core/dist/runtime-v2/principle-tree/ledger-codec.d.ts.map +1 -1
- package/core/dist/runtime-v2/principle-tree/ledger-codec.js +3 -6
- package/core/dist/runtime-v2/principle-tree/ledger-codec.js.map +1 -1
- package/core/dist/runtime-v2/principle-tree/rule-candidate-binding.d.ts +12 -0
- package/core/dist/runtime-v2/principle-tree/rule-candidate-binding.d.ts.map +1 -0
- package/core/dist/runtime-v2/principle-tree/rule-candidate-binding.js +129 -0
- package/core/dist/runtime-v2/principle-tree/rule-candidate-binding.js.map +1 -0
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.js +70 -6
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +15 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/types/ledger-store.d.ts +3 -0
- package/core/dist/runtime-v2/types/ledger-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/ledger-store.js.map +1 -1
- package/core/dist/runtime-v2/types/rule-candidate-binding.d.ts +98 -0
- package/core/dist/runtime-v2/types/rule-candidate-binding.d.ts.map +1 -0
- package/core/dist/runtime-v2/types/rule-candidate-binding.js +2 -0
- package/core/dist/runtime-v2/types/rule-candidate-binding.js.map +1 -0
- 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 +1 -0
- package/core/dist/telemetry-event.js.map +1 -1
- package/core/package.json +1 -1
- package/host-runtime/dist/internalization-consumer-cycle.js +12 -0
- package/host-runtime/dist/internalization-consumer-governance.js +4 -0
- package/host-runtime/package.json +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +4 -0
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +10 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/services/demo-story-a-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/demo-story-a-runner.js +43 -2
- package/pd-cli/dist/services/demo-story-a-runner.js.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts +8 -30
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +76 -124
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/bundle.js +468 -465
- package/release-manager/package.json +1 -1
|
@@ -22,6 +22,7 @@ import { handleReceiptsRoute, disposeReceiptsModels } from './routes/receipts.js
|
|
|
22
22
|
import { handleApprovalsGroupedRoute, disposeApprovalsGroupedModels } from './routes/approvals-grouped.js';
|
|
23
23
|
import { handleGovernanceRoute, handleGovernanceExperienceRoute, resolveOwnerConfigSnapshot, disposeGovernanceModels } from './routes/governance.js';
|
|
24
24
|
import { handleOwnerDecisionsRoute } from './routes/owner-decisions.js';
|
|
25
|
+
import { handleRuleCandidateBindingsRoute } from './routes/rule-candidate-bindings.js';
|
|
25
26
|
import { handleEvidenceOutcomesRoute } from './routes/evidence-outcomes.js';
|
|
26
27
|
import { handleDesignGateRoute } from './routes/design-gate.js';
|
|
27
28
|
import { handleOwnerDecisionInboxRoute, handleOwnerDecisionViewRoute, handleOwnerDecisionLibraryRoute, parseOwnerDecisionViewSubPath } from './routes/owner-decision.js';
|
|
@@ -485,6 +486,16 @@ function handleRequest(services) {
|
|
|
485
486
|
asyncHandler(() => handleGovernanceRoute(req, res, services.workspaceDir))(req, res);
|
|
486
487
|
return;
|
|
487
488
|
}
|
|
489
|
+
if (urlPath === '/api/v1/governance/rule-candidate-bindings' || urlPath.startsWith('/api/v1/governance/rule-candidate-bindings/')) {
|
|
490
|
+
const { ownerId, credentialId } = resolveOwnerIdentity(process.env, defaultOwnerIdentityHomeDir());
|
|
491
|
+
asyncHandler(() => handleRuleCandidateBindingsRoute(req, res, {
|
|
492
|
+
workspaceDir: services.workspaceDir,
|
|
493
|
+
subPath: urlPath.slice('/api/v1/governance/rule-candidate-bindings'.length),
|
|
494
|
+
ownerIdentity: services.authConfig.isEnabled() && ownerId !== null && credentialId !== null
|
|
495
|
+
? { ownerId, credentialId } : null,
|
|
496
|
+
}))(req, res);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
488
499
|
// PRI-629: GET/POST /api/v1/governance/owner-decisions — unified Owner Inbox
|
|
489
500
|
// (read projection + resolution). Identity derived server-side (SPEC §29):
|
|
490
501
|
// configured owner when registered, else the authenticated console operator.
|
|
@@ -2,6 +2,7 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { SqliteConnection, SqliteApprovalQueueStore, SqliteActivationStateStore, SqlitePIArtifactStore, ActivationDispatcher, PromptWriter, DeferArchiveWriter, RuleHostWriter, createProductionGateDeps, ApprovalCompletionService, ApprovalQueue, mapConfidenceToLabel, isArtifactRevisionOf, detectPromptReplacementTarget, buildOwnerRevisionArtifact, PrincipleTreeLedgerAdapter, MVP_CHANNELS, } from '@principles/core/runtime-v2';
|
|
4
4
|
import { resolveLedgerPrincipleId } from './principle-id-resolution.js';
|
|
5
|
+
import { createArtifactPrincipleResolutionDeps } from './artifact-principle-resolver.js';
|
|
5
6
|
import { loadPdConfig, computeFlagsFromLoadResult } from '../config/pd-config-store.js';
|
|
6
7
|
import { resolveWorkspaceHostToolSemantics, checkPromptArtifactDeliverabilityById, operatorDeclaredBudgetResolution, resolveLivePromptInjectionProjection, runtimeBudgetObservationToResolution, selectConsoleRuntimeBudgetFacts, } from '@principles/host-runtime';
|
|
7
8
|
import { PROMPT_BUDGET_HOST_KINDS } from '@principles/core/runtime-v2';
|
|
@@ -459,17 +460,7 @@ export class ApprovalsConsoleModel {
|
|
|
459
460
|
// ids against the ledger and otherwise walks the candidate lineage
|
|
460
461
|
// (scribe → dreamer seed → candidateId → derivedFromPainIds).
|
|
461
462
|
const ledger = new PrincipleTreeLedgerAdapter({ stateDir });
|
|
462
|
-
const resolution = await resolveLedgerPrincipleId(artifact,
|
|
463
|
-
ledger,
|
|
464
|
-
getArtifactById: (id) => piArtifactStore.getArtifactById(id),
|
|
465
|
-
getTaskDiagnosticJson: (taskId) => {
|
|
466
|
-
const row = connection
|
|
467
|
-
.getDb()
|
|
468
|
-
.prepare('SELECT diagnostic_json FROM tasks WHERE task_id = ?')
|
|
469
|
-
.get(taskId);
|
|
470
|
-
return row?.diagnostic_json ?? null;
|
|
471
|
-
},
|
|
472
|
-
});
|
|
463
|
+
const resolution = await resolveLedgerPrincipleId(artifact, createArtifactPrincipleResolutionDeps(connection, piArtifactStore, this.workspaceDir));
|
|
473
464
|
if (resolution.status === 'unresolved') {
|
|
474
465
|
return `ledger_activate_skipped: artifact ${artifactId} — ${resolution.reason}`;
|
|
475
466
|
}
|
|
@@ -653,6 +644,10 @@ export class ApprovalsConsoleModel {
|
|
|
653
644
|
// warn later. The dispatcher gate now blocks both, and the existing
|
|
654
645
|
// post-commit upgrade below keeps its role unchanged.
|
|
655
646
|
ledgerIdentity: {
|
|
647
|
+
getCandidateKind: (candidateId) => {
|
|
648
|
+
const row = connection.getDb().prepare('SELECT recommendation_kind FROM principle_candidates WHERE candidate_id = ?').get(candidateId);
|
|
649
|
+
return row !== null && typeof row === 'object' && Object.hasOwn(row, 'recommendation_kind') ? Reflect.get(row, 'recommendation_kind') : undefined;
|
|
650
|
+
},
|
|
656
651
|
ledger: new PrincipleTreeLedgerAdapter({ stateDir: `${this.workspaceDir}/.state` }),
|
|
657
652
|
getArtifactById: artifactReadModel.getArtifactById,
|
|
658
653
|
getTaskDiagnosticJson: (taskId) => {
|
|
@@ -939,6 +934,10 @@ export class ApprovalsConsoleModel {
|
|
|
939
934
|
writers: [new PromptWriter()],
|
|
940
935
|
approvalQueueStore: queueStore,
|
|
941
936
|
ledgerIdentity: {
|
|
937
|
+
getCandidateKind: (candidateId) => {
|
|
938
|
+
const row = connection.getDb().prepare('SELECT recommendation_kind FROM principle_candidates WHERE candidate_id = ?').get(candidateId);
|
|
939
|
+
return row !== null && typeof row === 'object' && Object.hasOwn(row, 'recommendation_kind') ? Reflect.get(row, 'recommendation_kind') : undefined;
|
|
940
|
+
},
|
|
942
941
|
ledger: new PrincipleTreeLedgerAdapter({ stateDir: `${this.workspaceDir}/.state` }),
|
|
943
942
|
getArtifactById: async (id) => {
|
|
944
943
|
const rec = await artifactStore.getArtifactById(id);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { reviseRuleBindingOnce } from '@principles/core/runtime-v2';
|
|
2
|
+
import type { RuleCandidateBindingRequest, RuleCandidateBindingMutationResult } from '@principles/core/runtime-v2';
|
|
3
|
+
import type { RuleBindingReviewView, RuleBindingQueueView } from '../../shared/rule-candidate-binding-contract.js';
|
|
4
|
+
import { ActivationsConsoleModel } from './ActivationsConsoleModel.js';
|
|
5
|
+
/** Derived review only. Binding authority stays inside the locked core Ledger writer. */
|
|
6
|
+
export declare class RuleCandidateBindingConsoleModel {
|
|
7
|
+
private readonly workspaceDir;
|
|
8
|
+
constructor(workspaceDir: string);
|
|
9
|
+
private ledger;
|
|
10
|
+
list(): Promise<RuleBindingQueueView>;
|
|
11
|
+
review(candidateId: string, search: string): Promise<{
|
|
12
|
+
ok: true;
|
|
13
|
+
review: RuleBindingReviewView;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
reason: string;
|
|
17
|
+
nextAction: string;
|
|
18
|
+
}>;
|
|
19
|
+
mutate(candidateId: string, request: RuleCandidateBindingRequest, actorId: string): Promise<RuleCandidateBindingMutationResult & {
|
|
20
|
+
revision?: Awaited<ReturnType<typeof reviseRuleBindingOnce>>;
|
|
21
|
+
operations?: Awaited<ReturnType<ActivationsConsoleModel['getActivations']>>;
|
|
22
|
+
operationsScope?: string;
|
|
23
|
+
stopPath?: string;
|
|
24
|
+
nextAction?: string;
|
|
25
|
+
}>;
|
|
26
|
+
revise(candidateId: string, input: {
|
|
27
|
+
expectedBindingRevision: number;
|
|
28
|
+
expectedScribeTaskId: string;
|
|
29
|
+
expectedTaskRevisionEpoch: number;
|
|
30
|
+
requestId: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
status: 'refused';
|
|
33
|
+
reason: string;
|
|
34
|
+
nextAction: string;
|
|
35
|
+
} | {
|
|
36
|
+
status: 'revision_started' | 'revision_already_started';
|
|
37
|
+
scribeTaskId: string;
|
|
38
|
+
taskRevisionEpoch: number;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { createRuntimeStateHandle, PrincipleTreeLedgerAdapter, reviseRuleBindingOnce, } from '@principles/core/runtime-v2';
|
|
4
|
+
import { ActivationsConsoleModel } from './ActivationsConsoleModel.js';
|
|
5
|
+
function record(value) {
|
|
6
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function stringField(value, key) {
|
|
9
|
+
return record(value) && typeof value[key] === 'string' ? value[key] : '';
|
|
10
|
+
}
|
|
11
|
+
/** Derived review only. Binding authority stays inside the locked core Ledger writer. */
|
|
12
|
+
export class RuleCandidateBindingConsoleModel {
|
|
13
|
+
workspaceDir;
|
|
14
|
+
constructor(workspaceDir) {
|
|
15
|
+
this.workspaceDir = workspaceDir;
|
|
16
|
+
}
|
|
17
|
+
ledger(stateManager) {
|
|
18
|
+
return new PrincipleTreeLedgerAdapter({
|
|
19
|
+
stateDir: path.join(this.workspaceDir, '.state'),
|
|
20
|
+
reviewSources: {
|
|
21
|
+
loadCandidateMaterial: async (candidateId) => {
|
|
22
|
+
const candidate = await stateManager.getCandidate(candidateId);
|
|
23
|
+
if (!candidate)
|
|
24
|
+
return null;
|
|
25
|
+
const [task, run, artifact] = await Promise.all([
|
|
26
|
+
stateManager.getTask(candidate.taskId), stateManager.getRun(candidate.sourceRunId),
|
|
27
|
+
stateManager.getArtifact(candidate.artifactId),
|
|
28
|
+
]);
|
|
29
|
+
const parentTask = task?.taskKind === 'diag_router' && task.inputRef ? await stateManager.getTask(task.inputRef) : null;
|
|
30
|
+
return { candidate, task, run, artifact, parentTask };
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async list() {
|
|
36
|
+
// A fresh workspace with no state.db simply has no binding queue yet;
|
|
37
|
+
// 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: [] };
|
|
40
|
+
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
41
|
+
try {
|
|
42
|
+
const ledger = this.ledger(handle.stateManager);
|
|
43
|
+
// Split diagnoses commit their rule candidates on diag_router sub-tasks;
|
|
44
|
+
// the queue must surface both provenance shapes, not only direct
|
|
45
|
+
// diagnostician commits.
|
|
46
|
+
const tasks = [
|
|
47
|
+
...await handle.stateManager.listTasks({ taskKind: 'diagnostician' }),
|
|
48
|
+
...await handle.stateManager.listTasks({ taskKind: 'diag_router' }),
|
|
49
|
+
];
|
|
50
|
+
const items = [];
|
|
51
|
+
for (const task of tasks) {
|
|
52
|
+
for (const candidate of await handle.stateManager.getCandidatesByTaskId(task.taskId)) {
|
|
53
|
+
if (candidate.rawRecommendationKind !== 'rule')
|
|
54
|
+
continue;
|
|
55
|
+
const identity = ledger.resolveCandidatePrincipleIdentity(candidate.candidateId, 'rule');
|
|
56
|
+
items.push({ candidateId: candidate.candidateId, text: candidate.description || candidate.title, reason: identity.status === 'unresolved' ? identity.reason : 'bound' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { items };
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
await handle.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async review(candidateId, search) {
|
|
66
|
+
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir, readonly: true, bootstrapIfMissing: false });
|
|
67
|
+
try {
|
|
68
|
+
const result = await this.ledger(handle.stateManager).createRuleCandidateBindingReview(candidateId, { search, limit: 20 });
|
|
69
|
+
if (!result.ok)
|
|
70
|
+
return result;
|
|
71
|
+
const { candidateMaterial: material } = result;
|
|
72
|
+
return { ok: true, review: {
|
|
73
|
+
candidateId, candidateText: stringField(material.candidate, 'description') || stringField(material.candidate, 'title'),
|
|
74
|
+
sourcePainId: stringField(Reflect.get(material, 'parentTask'), 'inputRef') || stringField(material.task, 'inputRef'),
|
|
75
|
+
evidence: stringField(material.artifact, 'contentJson') || stringField(material.candidate, 'sourceRecommendationJson'),
|
|
76
|
+
candidateDigest: result.reviewedCandidateDigest,
|
|
77
|
+
currentRevision: result.currentRevision,
|
|
78
|
+
currentBinding: result.currentBinding,
|
|
79
|
+
eligibleTargets: result.eligibleTargets.map(({ principle, reviewedPrincipleDigest }) => ({
|
|
80
|
+
principleId: principle.id, text: principle.text, status: principle.status, version: principle.version, digest: reviewedPrincipleDigest,
|
|
81
|
+
})),
|
|
82
|
+
resumeNotice: '关联后自动启动一次现有配置的正文修订与代码生成、验证;沿用现有调用预算和超时。失败会保留关联与旧工件,不会自动循环,也不会批准或启用规则。',
|
|
83
|
+
} };
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await handle.close();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async mutate(candidateId, request, actorId) {
|
|
90
|
+
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir });
|
|
91
|
+
try {
|
|
92
|
+
const ledger = this.ledger(handle.stateManager);
|
|
93
|
+
const result = await ledger.mutateRuleCandidateBinding({ candidateId, request, owner: { actorId, source: 'authenticated_console' } });
|
|
94
|
+
if (!result.ok)
|
|
95
|
+
return result;
|
|
96
|
+
if (request.action === 'bind') {
|
|
97
|
+
// Replays also resume the same cause: a crash after Ledger commit must not require another consent.
|
|
98
|
+
try {
|
|
99
|
+
const revision = await reviseRuleBindingOnce({ stateManager: handle.stateManager, ledger: { resolveForCandidate: async (id) => ledger.resolveCandidatePrincipleIdentity(id, 'rule') }, candidateId, expectedBindingRevision: result.binding.revision });
|
|
100
|
+
return { ...result, revision };
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return { ...result, revision: { status: 'refused', reason: 'revision_source_unavailable', nextAction: '关联已保存。重试相同请求以恢复同一次修订,或使用恢复入口;不要重新关联。' } };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Revoke is independent of present target eligibility and never generates or deactivates anything.
|
|
107
|
+
let operations;
|
|
108
|
+
try {
|
|
109
|
+
operations = await new ActivationsConsoleModel(this.workspaceDir).getActivations();
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
operations = { status: 'degraded', activations: [], reason: 'activation_source_unavailable', nextAction: '运行记录暂不可读,请重新查看规则运行列表;不能据此认定没有运行中的规则。' };
|
|
113
|
+
}
|
|
114
|
+
return { ...result, operations, operationsScope: 'workspace', stopPath: '/activation', nextAction: '归属已撤回。已运行规则须在规则运行列表另行停用;撤回前已通过最终检查的在途操作仍可能完成。' };
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
await handle.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async revise(candidateId, input) {
|
|
121
|
+
const handle = await createRuntimeStateHandle({ workspaceDir: this.workspaceDir });
|
|
122
|
+
try {
|
|
123
|
+
const ledger = this.ledger(handle.stateManager);
|
|
124
|
+
return await reviseRuleBindingOnce({ stateManager: handle.stateManager, ledger: { resolveForCandidate: async (id) => ledger.resolveCandidatePrincipleIdentity(id, 'rule') }, candidateId, ...input });
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await handle.close();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { PrincipleTreeLedgerAdapter } from '@principles/core/runtime-v2';
|
|
2
1
|
import type { PIArtifactRecord, SqliteConnection } from '@principles/core/runtime-v2';
|
|
2
|
+
import { type LedgerResolutionDeps } from './principle-id-resolution.js';
|
|
3
3
|
export interface ArtifactPrincipleResolutionDeps {
|
|
4
|
-
readonly ledger:
|
|
4
|
+
readonly ledger: LedgerResolutionDeps['ledger'];
|
|
5
5
|
readonly getArtifactById: (artifactId: string) => Promise<PIArtifactRecord | null>;
|
|
6
6
|
/** Read one column from the tasks table (same workspace as the caller). */
|
|
7
7
|
readonly getTaskDiagnosticJson: (taskId: string) => string | null;
|
|
@@ -20,8 +20,17 @@ function isRecord(value) {
|
|
|
20
20
|
* per model call, not per artifact.
|
|
21
21
|
*/
|
|
22
22
|
export function createArtifactPrincipleResolutionDeps(conn, artifactStore, workspaceDir) {
|
|
23
|
+
const adapter = new PrincipleTreeLedgerAdapter({ stateDir: path.join(workspaceDir, '.state') });
|
|
23
24
|
return {
|
|
24
|
-
ledger:
|
|
25
|
+
ledger: {
|
|
26
|
+
isAvailable: () => adapter.isAvailable(),
|
|
27
|
+
hasPrinciple: (id) => adapter.hasPrinciple(id),
|
|
28
|
+
listForCandidate: (id) => adapter.listForCandidate(id),
|
|
29
|
+
resolveForCandidate: async (id) => {
|
|
30
|
+
const row = conn.getDb().prepare('SELECT recommendation_kind FROM principle_candidates WHERE candidate_id = ?').get(id);
|
|
31
|
+
return adapter.resolveCandidatePrincipleIdentity(id, isRecord(row) ? row.recommendation_kind : undefined);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
25
34
|
getArtifactById: (artifactId) => artifactStore.getArtifactById(artifactId),
|
|
26
35
|
getTaskDiagnosticJson: (taskId) => {
|
|
27
36
|
const row = conn
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { PIArtifactRecord, PIArtifactSnapshot } from '@principles/core/runtime-v2';
|
|
1
|
+
import type { CandidatePrincipleIdentityResolution, PIArtifactRecord, PIArtifactSnapshot } from '@principles/core/runtime-v2';
|
|
2
2
|
import type { PrincipleTreeLedgerAdapter } from '@principles/core/runtime-v2';
|
|
3
3
|
/**
|
|
4
4
|
* PRI-768 v5 follow-up (audit findings F3/F4): resolve the LEDGER principle id
|
|
5
5
|
* behind an approval artifact.
|
|
6
6
|
*
|
|
7
|
-
* F4: `
|
|
7
|
+
* F4: `resolveLedgerActivationId`'s last fallback returns `principleDraft.title`, and
|
|
8
8
|
* `ledger.activatePrinciple(<title>)` then always fails ("Cannot update missing
|
|
9
9
|
* principle") because ledger keys are UUIDs, never titles. A candidate id must
|
|
10
10
|
* be validated against the ledger before it is used as an update key.
|
|
@@ -32,19 +32,14 @@ export type LedgerPrincipleResolution = {
|
|
|
32
32
|
reason: string;
|
|
33
33
|
};
|
|
34
34
|
export interface LedgerResolutionDeps {
|
|
35
|
-
ledger: PrincipleTreeLedgerAdapter
|
|
35
|
+
ledger: Pick<PrincipleTreeLedgerAdapter, 'isAvailable' | 'hasPrinciple' | 'listForCandidate'> & {
|
|
36
|
+
resolveForCandidate?: (candidateId: string) => Promise<CandidatePrincipleIdentityResolution>;
|
|
37
|
+
};
|
|
36
38
|
getArtifactById: (artifactId: string) => Promise<PIArtifactRecord | null>;
|
|
37
39
|
/** Read one column from the tasks table; null when the row is missing. */
|
|
38
40
|
getTaskDiagnosticJson: (taskId: string) => string | null;
|
|
39
41
|
}
|
|
40
42
|
export declare function toResolutionSnapshot(record: PIArtifactRecord): PIArtifactSnapshot;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Resolve the ledger principle id for an approval artifact. Direct hits
|
|
45
|
-
* (sourcePrincipleId column / contentJson ids) are validated against the
|
|
46
|
-
* ledger before being trusted; otherwise the candidate lineage is walked and
|
|
47
|
-
* the ledger must resolve that candidate to EXACTLY ONE principle (multiple
|
|
48
|
-
* matches stay unresolved — ambiguity must not be silently collapsed).
|
|
49
|
-
*/
|
|
43
|
+
export { candidateIdFromDreamerTaskId } from '@principles/core/runtime-v2';
|
|
44
|
+
/** All Console read models use the activation boundary's fail-closed identity semantics. */
|
|
50
45
|
export declare function resolveLedgerPrincipleId(artifact: PIArtifactRecord, deps: LedgerResolutionDeps): Promise<LedgerPrincipleResolution>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveLedgerActivationId } from '@principles/core/runtime-v2';
|
|
2
2
|
export function toResolutionSnapshot(record) {
|
|
3
3
|
return {
|
|
4
4
|
artifactId: record.artifactId,
|
|
@@ -13,98 +13,11 @@ export function toResolutionSnapshot(record) {
|
|
|
13
13
|
updatedAt: record.updatedAt,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
export function candidateIdFromDreamerTaskId(taskId) {
|
|
19
|
-
if (!taskId || !taskId.startsWith(DREAMER_TASK_PREFIX))
|
|
20
|
-
return null;
|
|
21
|
-
const withoutPrefix = taskId.slice(DREAMER_TASK_PREFIX.length);
|
|
22
|
-
const lastDash = withoutPrefix.lastIndexOf('-');
|
|
23
|
-
if (lastDash <= 0)
|
|
24
|
-
return null;
|
|
25
|
-
const candidateId = withoutPrefix.slice(0, lastDash);
|
|
26
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(candidateId)
|
|
27
|
-
? candidateId
|
|
28
|
-
: null;
|
|
29
|
-
}
|
|
30
|
-
function isRecord(value) {
|
|
31
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
32
|
-
}
|
|
33
|
-
function readDreamerArtifactId(artifact) {
|
|
34
|
-
try {
|
|
35
|
-
const parsed = JSON.parse(artifact.contentJson);
|
|
36
|
-
if (isRecord(parsed) && Object.hasOwn(parsed, 'sourceTrace')) {
|
|
37
|
-
const trace = parsed.sourceTrace;
|
|
38
|
-
if (isRecord(trace) && Object.hasOwn(trace, 'dreamerArtifactId')) {
|
|
39
|
-
const id = trace.dreamerArtifactId;
|
|
40
|
-
if (typeof id === 'string' && id.trim() !== '')
|
|
41
|
-
return id;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
// contentJson is untrusted; lineage fallback below still applies.
|
|
47
|
-
}
|
|
48
|
-
const lineage = artifact.lineageArtifactIds ?? [];
|
|
49
|
-
const dreamer = lineage.find((id) => typeof id === 'string' && id.includes('-dreamer-'));
|
|
50
|
-
return dreamer ?? null;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Resolve the ledger principle id for an approval artifact. Direct hits
|
|
54
|
-
* (sourcePrincipleId column / contentJson ids) are validated against the
|
|
55
|
-
* ledger before being trusted; otherwise the candidate lineage is walked and
|
|
56
|
-
* the ledger must resolve that candidate to EXACTLY ONE principle (multiple
|
|
57
|
-
* matches stay unresolved — ambiguity must not be silently collapsed).
|
|
58
|
-
*/
|
|
16
|
+
export { candidateIdFromDreamerTaskId } from '@principles/core/runtime-v2';
|
|
17
|
+
/** All Console read models use the activation boundary's fail-closed identity semantics. */
|
|
59
18
|
export async function resolveLedgerPrincipleId(artifact, deps) {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const dreamerArtifactId = readDreamerArtifactId(artifact);
|
|
65
|
-
if (!dreamerArtifactId) {
|
|
66
|
-
return {
|
|
67
|
-
status: 'unresolved',
|
|
68
|
-
reason: `no ledger principle for "${direct ?? 'no id'}" and artifact has no dreamer lineage`,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
const dreamerArtifact = await deps.getArtifactById(dreamerArtifactId);
|
|
72
|
-
if (!dreamerArtifact) {
|
|
73
|
-
return { status: 'unresolved', reason: `dreamer artifact ${dreamerArtifactId} not found` };
|
|
74
|
-
}
|
|
75
|
-
// The dreamer TASK seed is the authoritative carrier of the candidate id;
|
|
76
|
-
// the task-id spelling is only a fallback.
|
|
77
|
-
let candidateId = candidateIdFromDreamerTaskId(dreamerArtifact.sourceTaskId);
|
|
78
|
-
if (dreamerArtifact.sourceTaskId) {
|
|
79
|
-
const diagnosticJson = deps.getTaskDiagnosticJson(dreamerArtifact.sourceTaskId);
|
|
80
|
-
if (diagnosticJson) {
|
|
81
|
-
try {
|
|
82
|
-
const parsed = JSON.parse(diagnosticJson);
|
|
83
|
-
if (isRecord(parsed) && Object.hasOwn(parsed, 'candidateId')) {
|
|
84
|
-
const value = parsed.candidateId;
|
|
85
|
-
if (typeof value === 'string' && value.trim() !== '')
|
|
86
|
-
candidateId = value.trim();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
// Malformed seed JSON — fall back to the task-id derivation above.
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (!candidateId) {
|
|
95
|
-
return { status: 'unresolved', reason: 'dreamer lineage carries no candidate id' };
|
|
96
|
-
}
|
|
97
|
-
const matches = deps.ledger.listForCandidate(candidateId);
|
|
98
|
-
if (matches.length === 1) {
|
|
99
|
-
const [entry] = matches;
|
|
100
|
-
if (entry)
|
|
101
|
-
return { status: 'resolved', principleId: entry.id, how: 'candidate_lineage' };
|
|
102
|
-
}
|
|
103
|
-
if (matches.length === 0) {
|
|
104
|
-
return { status: 'unresolved', reason: `ledger has no principle derived from candidate ${candidateId}` };
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
status: 'unresolved',
|
|
108
|
-
reason: `candidate ${candidateId} maps to ${matches.length} ledger principles; refusing to guess`,
|
|
109
|
-
};
|
|
19
|
+
const result = await resolveLedgerActivationId(toResolutionSnapshot(artifact), deps);
|
|
20
|
+
return result.status === 'resolved'
|
|
21
|
+
? { status: 'resolved', principleId: result.principleId, how: result.how === 'direct_validated' ? 'direct' : 'candidate_lineage' }
|
|
22
|
+
: result;
|
|
110
23
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
export interface RuleCandidateBindingRouteContext {
|
|
3
|
+
workspaceDir: string;
|
|
4
|
+
subPath: string;
|
|
5
|
+
ownerIdentity: {
|
|
6
|
+
ownerId: string;
|
|
7
|
+
credentialId: string;
|
|
8
|
+
} | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function handleRuleCandidateBindingsRoute(req: IncomingMessage, res: ServerResponse, ctx: RuleCandidateBindingRouteContext): Promise<void>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RuleCandidateBindingConsoleModel } from '../models/RuleCandidateBindingConsoleModel.js';
|
|
2
|
+
import { readBody } from '../utils/request.js';
|
|
3
|
+
import { sendSuccess, sendError, sendBadRequest, sendMethodNotAllowed } from '../utils/response.js';
|
|
4
|
+
function closed(value, keys) {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
6
|
+
&& Object.keys(value).every(key => keys.includes(key));
|
|
7
|
+
}
|
|
8
|
+
function text(value, limit) {
|
|
9
|
+
return typeof value === 'string' && value.trim().length > 0 && value.length <= limit;
|
|
10
|
+
}
|
|
11
|
+
function revision(value) {
|
|
12
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
13
|
+
}
|
|
14
|
+
function digest(value) { return typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value); }
|
|
15
|
+
function bindingBody(raw) {
|
|
16
|
+
const common = ['action', 'expectedRevision', 'reason', 'requestId', 'resumeOnce'];
|
|
17
|
+
if (!closed(raw, [...common, 'principleId', 'expectedCandidateDigest', 'expectedPrincipleDigest'])
|
|
18
|
+
|| !revision(raw.expectedRevision) || !text(raw.reason, 2000) || !text(raw.requestId, 200))
|
|
19
|
+
return null;
|
|
20
|
+
if (raw.action === 'bind' && raw.resumeOnce === true && text(raw.principleId, 128)
|
|
21
|
+
&& digest(raw.expectedCandidateDigest) && digest(raw.expectedPrincipleDigest)) {
|
|
22
|
+
return { action: 'bind', principleId: raw.principleId, expectedRevision: raw.expectedRevision,
|
|
23
|
+
expectedCandidateDigest: raw.expectedCandidateDigest, expectedPrincipleDigest: raw.expectedPrincipleDigest,
|
|
24
|
+
reason: raw.reason, requestId: raw.requestId, resumeOnce: true };
|
|
25
|
+
}
|
|
26
|
+
if (raw.action === 'revoke' && raw.resumeOnce === false && closed(raw, common)) {
|
|
27
|
+
return { action: 'revoke', expectedRevision: raw.expectedRevision, reason: raw.reason, requestId: raw.requestId, resumeOnce: false };
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function failure(res, result) {
|
|
32
|
+
const status = result.reason.includes('unavailable') || result.reason.includes('corrupt') ? 503
|
|
33
|
+
: result.reason === 'candidate_missing' ? 404 : 409;
|
|
34
|
+
// The UI surfaces `message` first (api.ts request()); carrying the reason in
|
|
35
|
+
// it keeps the specific cause — stale revision, digest mismatch, ineligible
|
|
36
|
+
// target — visible to the Owner instead of a generic refusal.
|
|
37
|
+
sendError(res, status, result.reason, `当前材料无法完成此操作(${result.reason})。`, { reason: result.reason, nextAction: result.nextAction });
|
|
38
|
+
}
|
|
39
|
+
export async function handleRuleCandidateBindingsRoute(req, res, ctx) {
|
|
40
|
+
// Auth precedes model construction and body parsing: a refused caller cannot create state.
|
|
41
|
+
if (!ctx.ownerIdentity) {
|
|
42
|
+
sendError(res, 403, 'owner_authentication_required', '请先完成控制台认证并配置 Owner 身份。', { nextAction: '在设置中确认 Owner 身份后重试。' });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const model = new RuleCandidateBindingConsoleModel(ctx.workspaceDir);
|
|
46
|
+
const match = /^\/([^/]+)(?:\/(review|revise-once))?$/.exec(ctx.subPath);
|
|
47
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
48
|
+
try {
|
|
49
|
+
if ((ctx.subPath === '' || ctx.subPath === '/') && req.method === 'GET') {
|
|
50
|
+
sendSuccess(res, await model.list());
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!match?.[1]) {
|
|
54
|
+
sendError(res, 404, 'not_found', '未找到该关联入口。');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const candidateId = decodeURIComponent(match[1]);
|
|
58
|
+
if (match[2] === 'review') {
|
|
59
|
+
if (req.method !== 'GET') {
|
|
60
|
+
sendMethodNotAllowed(res);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const search = url.searchParams.get('search') ?? '';
|
|
64
|
+
if (search.length > 200) {
|
|
65
|
+
sendBadRequest(res, '搜索内容最多 200 字。');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const result = await model.review(candidateId, search);
|
|
69
|
+
if (result.ok)
|
|
70
|
+
sendSuccess(res, result.review);
|
|
71
|
+
else
|
|
72
|
+
failure(res, result);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (req.method !== 'POST') {
|
|
76
|
+
sendMethodNotAllowed(res);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let raw;
|
|
80
|
+
try {
|
|
81
|
+
raw = JSON.parse(await readBody(req));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
sendBadRequest(res, '请求必须是有效的 JSON。');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (match[2] === 'revise-once') {
|
|
88
|
+
if (!closed(raw, ['expectedBindingRevision', 'expectedScribeTaskId', 'expectedTaskRevisionEpoch', 'requestId'])
|
|
89
|
+
|| !revision(raw.expectedBindingRevision) || raw.expectedBindingRevision < 1
|
|
90
|
+
|| !revision(raw.expectedTaskRevisionEpoch) || !text(raw.expectedScribeTaskId, 512) || !text(raw.requestId, 200)) {
|
|
91
|
+
sendBadRequest(res, '请提交当前关联、修订任务及版本;不接受身份或批准字段。');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const result = await model.revise(candidateId, { expectedBindingRevision: raw.expectedBindingRevision, expectedScribeTaskId: raw.expectedScribeTaskId,
|
|
95
|
+
expectedTaskRevisionEpoch: raw.expectedTaskRevisionEpoch, requestId: raw.requestId });
|
|
96
|
+
if (result.status === 'refused')
|
|
97
|
+
failure(res, result);
|
|
98
|
+
else
|
|
99
|
+
sendSuccess(res, result);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const request = bindingBody(raw);
|
|
103
|
+
if (!request) {
|
|
104
|
+
sendBadRequest(res, '关联与撤回必须使用各自完整字段;不接受身份、时间或批准字段。');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const result = await model.mutate(candidateId, request, ctx.ownerIdentity.ownerId);
|
|
108
|
+
if (result.ok)
|
|
109
|
+
sendSuccess(res, result);
|
|
110
|
+
else
|
|
111
|
+
failure(res, result);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
sendError(res, 503, 'binding_source_unavailable', '关联材料暂不可读。', { nextAction: '恢复当前工作区的数据来源后重新加载;不要假定操作已完成。' });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface RuleBindingTargetView {
|
|
2
|
+
principleId: string;
|
|
3
|
+
text: string;
|
|
4
|
+
status: string;
|
|
5
|
+
version: number;
|
|
6
|
+
digest: string;
|
|
7
|
+
}
|
|
8
|
+
export interface RuleBindingReviewView {
|
|
9
|
+
candidateId: string;
|
|
10
|
+
candidateText: string;
|
|
11
|
+
sourcePainId: string;
|
|
12
|
+
evidence: string;
|
|
13
|
+
candidateDigest: string;
|
|
14
|
+
currentRevision: number;
|
|
15
|
+
currentBinding: {
|
|
16
|
+
action: 'bind' | 'revoke';
|
|
17
|
+
principleId: string;
|
|
18
|
+
reason: string;
|
|
19
|
+
revision: number;
|
|
20
|
+
} | null;
|
|
21
|
+
eligibleTargets: RuleBindingTargetView[];
|
|
22
|
+
resumeNotice: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RuleBindingQueueView {
|
|
25
|
+
items: {
|
|
26
|
+
candidateId: string;
|
|
27
|
+
text: string;
|
|
28
|
+
reason: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/console/dist/ui/api.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ApiResponse } from "../types.js";
|
|
2
2
|
import type { OwnerDecisionsData, OwnerResolutionResultData, OwnerDecisionInboxData, OwnerDecisionLibraryData } from "./utils/validators.js";
|
|
3
3
|
import type { DesignGateAction, DesignGateDecision, DesignGateDeclaration, DesignGateScope } from "@principles/core/runtime-v2/internalization/design-gate-facts";
|
|
4
|
+
import type { RuleBindingReviewView, RuleBindingQueueView } from '../shared/rule-candidate-binding-contract.js';
|
|
5
|
+
import type { RuleCandidateBindingRequest } from '@principles/core/runtime-v2';
|
|
4
6
|
import type { GovernanceExperienceSnapshot, OwnerGovernanceView, OwnerDecisionViewCore } from '@principles/core/runtime-v2';
|
|
5
7
|
import type { OwnerIdentityViewData, OwnerIdentityRegisterData, OwnerIdentityUnregisterData } from "./utils/validators.js";
|
|
6
8
|
import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, FailedTaskDetailData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, UpdateRecoveryData, UpdateTransactionData, ApprovalRecordData, PrinciplesListData, CorePrinciplesData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData, RuleCodeOwnerReviewData, RuleCodeMutationData } from "./utils/validators.js";
|
|
@@ -41,6 +43,13 @@ export declare function shouldInvalidateSessionTokenOn401(requestToken: string |
|
|
|
41
43
|
declare function request(path: string, options?: RequestInit): Promise<ApiResponse<unknown>>;
|
|
42
44
|
declare function request<T>(path: string, options: RequestInit | undefined, validate: (value: unknown) => T | null): Promise<ApiResponse<T>>;
|
|
43
45
|
declare function checkAuth(): Promise<boolean>;
|
|
46
|
+
export declare function fetchRuleBindingQueue(): Promise<ApiResponse<RuleBindingQueueView>>;
|
|
47
|
+
export declare function fetchRuleBindingReview(candidateId: string, search?: string): Promise<ApiResponse<RuleBindingReviewView>>;
|
|
48
|
+
export declare function mutateRuleBinding(candidateId: string, body: RuleCandidateBindingRequest): Promise<ApiResponse<{
|
|
49
|
+
status: string;
|
|
50
|
+
revisionStatus?: string;
|
|
51
|
+
nextAction?: string;
|
|
52
|
+
}>>;
|
|
44
53
|
declare function fetchWorkspaces(): Promise<ApiResponse<WorkspaceEntryData[]>>;
|
|
45
54
|
declare function addWorkspace(name: string, path: string): Promise<ApiResponse<WorkspaceEntryData>>;
|
|
46
55
|
declare function removeWorkspace(name: string): Promise<ApiResponse<RemovedEnvelopeData>>;
|