principles-disciple 1.11.0 → 1.13.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/CHANGELOG.md +26 -0
- package/README.md +66 -0
- package/esbuild.config.js +1 -1
- package/openclaw.plugin.json +4 -4
- package/package.json +2 -3
- package/run-nocturnal.mjs +30 -0
- package/scripts/db-migrate.mjs +170 -0
- package/scripts/sync-plugin.mjs +250 -6
- package/src/commands/archive-impl.ts +136 -0
- package/src/commands/capabilities.ts +4 -2
- package/src/commands/context.ts +5 -1
- package/src/commands/disable-impl.ts +151 -0
- package/src/commands/evolution-status.ts +64 -19
- package/src/commands/export.ts +8 -6
- package/src/commands/focus.ts +8 -20
- package/src/commands/nocturnal-review.ts +5 -7
- package/src/commands/nocturnal-rollout.ts +1 -12
- package/src/commands/nocturnal-train.ts +21 -47
- package/src/commands/pain.ts +10 -5
- package/src/commands/principle-rollback.ts +4 -2
- package/src/commands/promote-impl.ts +274 -0
- package/src/commands/rollback-impl.ts +234 -0
- package/src/commands/rollback.ts +6 -3
- package/src/commands/samples.ts +2 -0
- package/src/commands/thinking-os.ts +3 -4
- package/src/commands/workflow-debug.ts +2 -1
- package/src/config/errors.ts +1 -0
- package/src/core/AGENTS.md +34 -0
- package/src/core/adaptive-thresholds.ts +4 -3
- package/src/core/code-implementation-storage.ts +241 -0
- package/src/core/config.ts +5 -2
- package/src/core/control-ui-db.ts +29 -10
- package/src/core/detection-funnel.ts +12 -7
- package/src/core/diagnostician-task-store.ts +156 -0
- package/src/core/dictionary.ts +4 -4
- package/src/core/empathy-keyword-matcher.ts +7 -3
- package/src/core/empathy-types.ts +13 -2
- package/src/core/event-log.ts +14 -6
- package/src/core/evolution-engine.ts +27 -31
- package/src/core/evolution-logger.ts +3 -2
- package/src/core/evolution-reducer.ts +110 -31
- package/src/core/evolution-types.ts +10 -0
- package/src/core/external-training-contract.ts +1 -0
- package/src/core/focus-history.ts +38 -24
- package/src/core/hygiene/tracker.ts +10 -6
- package/src/core/init.ts +5 -2
- package/src/core/migration.ts +3 -3
- package/src/core/model-deployment-registry.ts +6 -4
- package/src/core/model-training-registry.ts +5 -3
- package/src/core/nocturnal-arbiter.ts +13 -14
- package/src/core/nocturnal-artifact-lineage.ts +117 -0
- package/src/core/nocturnal-artificer.ts +257 -0
- package/src/core/nocturnal-candidate-scoring.ts +4 -2
- package/src/core/nocturnal-compliance.ts +67 -19
- package/src/core/nocturnal-dataset.ts +95 -2
- package/src/core/nocturnal-executability.ts +2 -3
- package/src/core/nocturnal-export.ts +6 -3
- package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
- package/src/core/nocturnal-trajectory-extractor.ts +10 -3
- package/src/core/nocturnal-trinity.ts +319 -61
- package/src/core/pain-context-extractor.ts +29 -15
- package/src/core/pain.ts +7 -5
- package/src/core/path-resolver.ts +16 -15
- package/src/core/paths.ts +2 -1
- package/src/core/pd-task-reconciler.ts +463 -0
- package/src/core/pd-task-service.ts +42 -0
- package/src/core/pd-task-store.ts +77 -0
- package/src/core/pd-task-types.ts +128 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
- package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
- package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
- package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
- package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
- package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
- package/src/core/principle-training-state.ts +95 -370
- package/src/core/principle-tree-ledger.ts +733 -0
- package/src/core/principle-tree-migration.ts +195 -0
- package/src/core/profile.ts +3 -1
- package/src/core/promotion-gate.ts +14 -18
- package/src/core/replay-engine.ts +562 -0
- package/src/core/risk-calculator.ts +6 -4
- package/src/core/rule-host-helpers.ts +39 -0
- package/src/core/rule-host-types.ts +82 -0
- package/src/core/rule-host.ts +245 -0
- package/src/core/rule-implementation-runtime.ts +38 -0
- package/src/core/schema/db-types.ts +16 -0
- package/src/core/schema/index.ts +26 -0
- package/src/core/schema/migration-runner.ts +207 -0
- package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
- package/src/core/schema/migrations/002-init-central.ts +122 -0
- package/src/core/schema/migrations/003-init-workflow.ts +55 -0
- package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
- package/src/core/schema/migrations/index.ts +31 -0
- package/src/core/schema/schema-definitions.ts +650 -0
- package/src/core/session-tracker.ts +6 -4
- package/src/core/shadow-observation-registry.ts +6 -3
- package/src/core/system-logger.ts +2 -2
- package/src/core/thinking-models.ts +182 -46
- package/src/core/thinking-os-parser.ts +156 -0
- package/src/core/training-program.ts +7 -7
- package/src/core/trajectory.ts +42 -36
- package/src/core/workspace-context.ts +77 -11
- package/src/core/workspace-dir-validation.ts +152 -0
- package/src/hooks/AGENTS.md +31 -0
- package/src/hooks/bash-risk.ts +3 -1
- package/src/hooks/edit-verification.ts +9 -5
- package/src/hooks/gate-block-helper.ts +5 -1
- package/src/hooks/gate.ts +152 -5
- package/src/hooks/gfi-gate.ts +9 -2
- package/src/hooks/lifecycle-routing.ts +124 -0
- package/src/hooks/lifecycle.ts +12 -12
- package/src/hooks/llm.ts +17 -109
- package/src/hooks/message-sanitize.ts +5 -3
- package/src/hooks/pain.ts +19 -15
- package/src/hooks/progressive-trust-gate.ts +7 -1
- package/src/hooks/prompt.ts +169 -60
- package/src/hooks/subagent.ts +5 -4
- package/src/hooks/thinking-checkpoint.ts +2 -0
- package/src/hooks/trajectory-collector.ts +15 -12
- package/src/http/principles-console-route.ts +31 -68
- package/src/i18n/commands.ts +2 -2
- package/src/index.ts +130 -40
- package/src/service/central-database.ts +131 -43
- package/src/service/central-health-service.ts +47 -0
- package/src/service/central-overview-service.ts +135 -0
- package/src/service/central-sync-service.ts +87 -0
- package/src/service/control-ui-query-service.ts +46 -36
- package/src/service/event-log-auditor.ts +261 -0
- package/src/service/evolution-query-service.ts +23 -22
- package/src/service/evolution-worker.ts +565 -261
- package/src/service/health-query-service.ts +213 -36
- package/src/service/nocturnal-runtime.ts +8 -4
- package/src/service/nocturnal-service.ts +503 -59
- package/src/service/nocturnal-target-selector.ts +5 -7
- package/src/service/runtime-summary-service.ts +2 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
- package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
- package/src/service/subagent-workflow/index.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
- package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
- package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
- package/src/service/subagent-workflow/types.ts +9 -4
- package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
- package/src/service/subagent-workflow/workflow-store.ts +71 -11
- package/src/service/trajectory-service.ts +2 -1
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/deep-reflect.ts +175 -209
- package/src/tools/model-index.ts +2 -1
- package/src/types/event-types.ts +2 -2
- package/src/types/principle-tree-schema.ts +29 -23
- package/src/utils/file-lock.ts +5 -3
- package/src/utils/io.ts +5 -2
- package/src/utils/nlp.ts +5 -46
- package/src/utils/node-vm-polyfill.ts +11 -0
- package/src/utils/plugin-logger.ts +2 -0
- package/src/utils/retry.ts +572 -0
- package/src/utils/subagent-probe.ts +1 -1
- package/templates/langs/en/core/AGENTS.md +0 -13
- package/templates/langs/en/core/SOUL.md +1 -31
- package/templates/langs/en/core/TOOLS.md +0 -4
- package/templates/langs/en/principles/THINKING_OS.md +77 -0
- package/templates/langs/en/skills/admin/SKILL.md +0 -1
- package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
- package/templates/langs/zh/core/AGENTS.md +0 -22
- package/templates/langs/zh/core/SOUL.md +1 -31
- package/templates/langs/zh/core/TOOLS.md +0 -4
- package/templates/langs/zh/principles/THINKING_OS.md +77 -0
- package/templates/langs/zh/skills/admin/SKILL.md +0 -1
- package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
- package/tests/commands/evolution-status.test.ts +119 -0
- package/tests/commands/implementation-lifecycle.test.ts +362 -0
- package/tests/core/code-implementation-storage.test.ts +398 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
- package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
- package/tests/core/nocturnal-artificer.test.ts +241 -0
- package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
- package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
- package/tests/core/pd-task-store.test.ts +126 -0
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
- package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
- package/tests/core/principle-training-state.test.ts +228 -1
- package/tests/core/principle-tree-ledger.test.ts +423 -0
- package/tests/core/regression-v1-9-1.test.ts +265 -0
- package/tests/core/replay-engine.test.ts +234 -0
- package/tests/core/rule-host-helpers.test.ts +120 -0
- package/tests/core/rule-host.test.ts +389 -0
- package/tests/core/rule-implementation-runtime.test.ts +64 -0
- package/tests/core/workspace-context.test.ts +53 -0
- package/tests/core/workspace-dir-validation.test.ts +272 -0
- package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
- package/tests/hooks/pain.test.ts +74 -10
- package/tests/hooks/prompt.test.ts +63 -1
- package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
- package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
- package/tests/service/data-endpoints-regression.test.ts +834 -0
- package/tests/service/evolution-worker.test.ts +0 -123
- package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
- package/tests/utils/nlp.test.ts +1 -19
- package/tests/utils/retry.test.ts +327 -0
- package/ui/src/App.tsx +1 -1
- package/ui/src/api.ts +4 -0
- package/ui/src/charts.tsx +366 -0
- package/ui/src/components/WorkspaceConfig.tsx +107 -75
- package/ui/src/i18n/ui.ts +89 -31
- package/ui/src/pages/EvolutionPage.tsx +1 -1
- package/ui/src/pages/OverviewPage.tsx +441 -81
- package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
- package/ui/src/styles.css +43 -0
- package/ui/src/types.ts +17 -1
- package/src/agents/nocturnal-dreamer.md +0 -152
- package/src/agents/nocturnal-philosopher.md +0 -138
- package/src/agents/nocturnal-reflector.md +0 -126
- package/src/agents/nocturnal-scribe.md +0 -164
- package/templates/workspace/.principles/00-kernel.md +0 -51
- package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
- package/templates/workspace/.principles/PRINCIPLES.md +0 -20
- package/templates/workspace/.principles/PROFILE.json +0 -54
- package/templates/workspace/.principles/PROFILE.schema.json +0 -56
- package/templates/workspace/.principles/THINKING_OS.md +0 -64
- package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
- package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
- package/templates/workspace/.principles/models/_INDEX.md +0 -27
- package/templates/workspace/.principles/models/first_principles.md +0 -62
- package/templates/workspace/.principles/models/marketing_4p.md +0 -52
- package/templates/workspace/.principles/models/porter_five.md +0 -63
- package/templates/workspace/.principles/models/swot.md +0 -60
- package/templates/workspace/.principles/models/user_story_map.md +0 -63
- package/templates/workspace/.state/WORKBOARD.json +0 -4
|
@@ -31,20 +31,18 @@
|
|
|
31
31
|
import * as fs from 'fs';
|
|
32
32
|
import * as path from 'path';
|
|
33
33
|
import { randomUUID } from 'crypto';
|
|
34
|
+
import type { RecentPainContext } from './evolution-worker.js';
|
|
34
35
|
import {
|
|
35
|
-
NocturnalTrajectoryExtractor,
|
|
36
36
|
createNocturnalTrajectoryExtractor,
|
|
37
37
|
computeThinkingModelDelta,
|
|
38
38
|
type NocturnalSessionSnapshot,
|
|
39
39
|
} from '../core/nocturnal-trajectory-extractor.js';
|
|
40
40
|
import {
|
|
41
41
|
NocturnalTargetSelector,
|
|
42
|
-
selectNocturnalTarget,
|
|
43
42
|
type NocturnalSelectionResult,
|
|
44
43
|
type SkipReason,
|
|
45
44
|
} from './nocturnal-target-selector.js';
|
|
46
45
|
import {
|
|
47
|
-
validateArtifact,
|
|
48
46
|
parseAndValidateArtifact,
|
|
49
47
|
validateTrinityDraft,
|
|
50
48
|
type NocturnalArtifact,
|
|
@@ -69,7 +67,29 @@ import {
|
|
|
69
67
|
type ThresholdSignals,
|
|
70
68
|
} from '../core/adaptive-thresholds.js';
|
|
71
69
|
import {
|
|
72
|
-
|
|
70
|
+
parseArtificerOutput,
|
|
71
|
+
resolveArtificerTargetRule,
|
|
72
|
+
shouldRunArtificer,
|
|
73
|
+
type ArtificerOutput,
|
|
74
|
+
type ArtificerTargetRuleResolution,
|
|
75
|
+
} from '../core/nocturnal-artificer.js';
|
|
76
|
+
import { validateRuleImplementationCandidate } from '../core/nocturnal-rule-implementation-validator.js';
|
|
77
|
+
import { refreshPrincipleLifecycle } from '../core/principle-internalization/lifecycle-refresh.js';
|
|
78
|
+
import {
|
|
79
|
+
createImplementationAssetDir,
|
|
80
|
+
deleteImplementationAssetDir,
|
|
81
|
+
getImplementationAssetRoot,
|
|
82
|
+
type CodeImplementationLineageMetadata,
|
|
83
|
+
} from '../core/code-implementation-storage.js';
|
|
84
|
+
import {
|
|
85
|
+
appendCandidateArtifactLineageRecord,
|
|
86
|
+
appendArtifactLineageRecord,
|
|
87
|
+
} from '../core/nocturnal-artifact-lineage.js';
|
|
88
|
+
import {
|
|
89
|
+
createImplementation,
|
|
90
|
+
deleteImplementation,
|
|
91
|
+
} from '../core/principle-tree-ledger.js';
|
|
92
|
+
import {
|
|
73
93
|
checkPreflight,
|
|
74
94
|
recordRunStart,
|
|
75
95
|
recordRunEnd,
|
|
@@ -78,6 +98,7 @@ import {
|
|
|
78
98
|
} from './nocturnal-runtime.js';
|
|
79
99
|
import { NocturnalPathResolver } from '../core/nocturnal-paths.js';
|
|
80
100
|
import { registerSample } from '../core/nocturnal-dataset.js';
|
|
101
|
+
import type { Implementation } from '../types/principle-tree-schema.js';
|
|
81
102
|
|
|
82
103
|
// ---------------------------------------------------------------------------
|
|
83
104
|
// Types
|
|
@@ -131,6 +152,27 @@ export interface NocturnalRunDiagnostics {
|
|
|
131
152
|
persisted: boolean;
|
|
132
153
|
/** Persistence path (if persisted) */
|
|
133
154
|
persistedPath?: string;
|
|
155
|
+
/** Code-candidate sidecar diagnostics */
|
|
156
|
+
artificer: NocturnalArtificerDiagnostics;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface NocturnalArtificerDiagnostics {
|
|
160
|
+
status: 'skipped' | 'validation_failed' | 'persisted_candidate';
|
|
161
|
+
reason?:
|
|
162
|
+
| 'behavioral_artifact_unavailable'
|
|
163
|
+
| 'no_deterministic_rule'
|
|
164
|
+
| 'insufficient_signal_density'
|
|
165
|
+
| 'missing_scribe_input'
|
|
166
|
+
| 'parse_failed'
|
|
167
|
+
| 'rule_mismatch'
|
|
168
|
+
| 'validator_rejected'
|
|
169
|
+
| 'persistence_failed';
|
|
170
|
+
ruleResolution: ArtificerTargetRuleResolution | null;
|
|
171
|
+
validationFailures: string[];
|
|
172
|
+
implementationId?: string;
|
|
173
|
+
artifactId?: string;
|
|
174
|
+
ruleId?: string;
|
|
175
|
+
persistedPath?: string;
|
|
134
176
|
}
|
|
135
177
|
|
|
136
178
|
/**
|
|
@@ -179,7 +221,27 @@ export interface NocturnalServiceOptions {
|
|
|
179
221
|
* When provided, the target selector uses it for ranking bias and diagnostics enrichment.
|
|
180
222
|
* This threads recent pain signals into sleep_reflection targeting without merging task kinds.
|
|
181
223
|
*/
|
|
182
|
-
painContext?:
|
|
224
|
+
painContext?: RecentPainContext;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Override the principleId (skip Selector stage).
|
|
228
|
+
* When provided with snapshotOverride, the Selector stage is skipped and the provided
|
|
229
|
+
* principleId and snapshot are used directly for Trinity execution.
|
|
230
|
+
* This unifies NocturnalWorkflowManager with executeNocturnalReflectionAsync.
|
|
231
|
+
*/
|
|
232
|
+
principleIdOverride?: string;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Override the snapshot (skip Selector stage).
|
|
236
|
+
* Must be provided together with principleIdOverride to skip Selector.
|
|
237
|
+
*/
|
|
238
|
+
snapshotOverride?: NocturnalSessionSnapshot;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Override the Artificer JSON output (for testing).
|
|
242
|
+
* When omitted, a deterministic local candidate is synthesized.
|
|
243
|
+
*/
|
|
244
|
+
artificerOutputOverride?: string;
|
|
183
245
|
}
|
|
184
246
|
|
|
185
247
|
// ---------------------------------------------------------------------------
|
|
@@ -209,8 +271,11 @@ function invokeStubReflector(
|
|
|
209
271
|
const hasGateBlocks = snapshot.stats.totalGateBlocks > 0;
|
|
210
272
|
|
|
211
273
|
// Detect what kind of signal is available and craft appropriate artifact
|
|
274
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all if/else branches
|
|
212
275
|
let badDecision: string;
|
|
276
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all if/else branches
|
|
213
277
|
let betterDecision: string;
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all if/else branches
|
|
214
279
|
let rationale: string;
|
|
215
280
|
|
|
216
281
|
if (hasGateBlocks) {
|
|
@@ -283,6 +348,272 @@ function persistArtifact(
|
|
|
283
348
|
return artifactPath;
|
|
284
349
|
}
|
|
285
350
|
|
|
351
|
+
function buildPainRefs(snapshot: NocturnalSessionSnapshot): string[] {
|
|
352
|
+
return snapshot.painEvents.map(
|
|
353
|
+
(painEvent) =>
|
|
354
|
+
`pain:${painEvent.source}:${painEvent.createdAt}:${(painEvent.reason ?? '').trim()}`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function buildGateBlockRefs(snapshot: NocturnalSessionSnapshot): string[] {
|
|
359
|
+
return snapshot.gateBlocks.map(
|
|
360
|
+
(gateBlock) =>
|
|
361
|
+
`gate:${gateBlock.toolName}:${gateBlock.createdAt}:${gateBlock.reason.trim()}`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* eslint-disable @typescript-eslint/max-params -- Reason: Function signature requires all parameters for type-safe artifact construction */
|
|
366
|
+
function buildDefaultArtificerOutput(
|
|
367
|
+
ruleId: string,
|
|
368
|
+
artifact: NocturnalArtifact,
|
|
369
|
+
sourceSnapshotRef: string,
|
|
370
|
+
sourcePainIds: string[],
|
|
371
|
+
sourceGateBlockIds: string[]
|
|
372
|
+
): ArtificerOutput {
|
|
373
|
+
return {
|
|
374
|
+
ruleId,
|
|
375
|
+
implementationType: 'code',
|
|
376
|
+
candidateSource: [
|
|
377
|
+
'export const meta = {',
|
|
378
|
+
` name: ${JSON.stringify(`nocturnal-${ruleId.toLowerCase()}`)},`,
|
|
379
|
+
' version: "1.0.0",',
|
|
380
|
+
` ruleId: ${JSON.stringify(ruleId)},`,
|
|
381
|
+
` coversCondition: ${JSON.stringify(artifact.betterDecision)},`,
|
|
382
|
+
'};',
|
|
383
|
+
'',
|
|
384
|
+
'export function evaluate(input, helpers) {',
|
|
385
|
+
' const riskPath = helpers.isRiskPath();',
|
|
386
|
+
' const toolName = helpers.getToolName();',
|
|
387
|
+
' const planStatus = helpers.getPlanStatus();',
|
|
388
|
+
" if (riskPath && toolName === 'write' && planStatus !== 'READY') {",
|
|
389
|
+
' return {',
|
|
390
|
+
" decision: 'requireApproval',",
|
|
391
|
+
' matched: true,',
|
|
392
|
+
` reason: ${JSON.stringify(artifact.rationale)},`,
|
|
393
|
+
' };',
|
|
394
|
+
' }',
|
|
395
|
+
' return {',
|
|
396
|
+
" decision: 'allow',",
|
|
397
|
+
' matched: false,',
|
|
398
|
+
" reason: 'not-applicable',",
|
|
399
|
+
' };',
|
|
400
|
+
'}',
|
|
401
|
+
].join('\n'),
|
|
402
|
+
helperUsage: ['isRiskPath', 'getToolName', 'getPlanStatus'],
|
|
403
|
+
expectedDecision: 'requireApproval',
|
|
404
|
+
rationale: artifact.rationale,
|
|
405
|
+
lineage: {
|
|
406
|
+
artifactKind: 'rule-implementation-candidate',
|
|
407
|
+
sourceSnapshotRef,
|
|
408
|
+
sourcePainIds,
|
|
409
|
+
sourceGateBlockIds,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/* eslint-disable @typescript-eslint/max-params -- Reason: Function signature requires all parameters for type-safe candidate persistence */
|
|
415
|
+
function persistCodeCandidate(
|
|
416
|
+
workspaceDir: string,
|
|
417
|
+
stateDir: string,
|
|
418
|
+
artifact: NocturnalArtifact,
|
|
419
|
+
selectedPrincipleId: string,
|
|
420
|
+
selectedSessionId: string,
|
|
421
|
+
parsedArtificer: ArtificerOutput
|
|
422
|
+
): NocturnalArtificerDiagnostics {
|
|
423
|
+
const implementationId = `IMPL-${randomUUID()}`;
|
|
424
|
+
const artifactId = `artifact-${randomUUID()}`;
|
|
425
|
+
const now = new Date().toISOString();
|
|
426
|
+
const assetRoot = getImplementationAssetRoot(stateDir, implementationId);
|
|
427
|
+
const entryPath = path.join(assetRoot, 'entry.js');
|
|
428
|
+
const lineage: CodeImplementationLineageMetadata = {
|
|
429
|
+
principleId: selectedPrincipleId,
|
|
430
|
+
ruleId: parsedArtificer.ruleId,
|
|
431
|
+
sourceSnapshotRef: artifact.sourceSnapshotRef,
|
|
432
|
+
sourcePainIds: [...parsedArtificer.lineage.sourcePainIds],
|
|
433
|
+
sourceGateBlockIds: [...parsedArtificer.lineage.sourceGateBlockIds],
|
|
434
|
+
sourceSessionId: selectedSessionId,
|
|
435
|
+
artificerArtifactId: artifactId,
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const implementation: Implementation = {
|
|
439
|
+
id: implementationId,
|
|
440
|
+
ruleId: parsedArtificer.ruleId,
|
|
441
|
+
type: 'code',
|
|
442
|
+
path: entryPath,
|
|
443
|
+
version: now,
|
|
444
|
+
coversCondition: parsedArtificer.rationale,
|
|
445
|
+
coveragePercentage: 0,
|
|
446
|
+
lifecycleState: 'candidate',
|
|
447
|
+
createdAt: now,
|
|
448
|
+
updatedAt: now,
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
createImplementation(stateDir, implementation);
|
|
453
|
+
createImplementationAssetDir(stateDir, implementationId, now, {
|
|
454
|
+
entrySource: parsedArtificer.candidateSource,
|
|
455
|
+
lineage,
|
|
456
|
+
});
|
|
457
|
+
appendCandidateArtifactLineageRecord(workspaceDir, {
|
|
458
|
+
artifactId,
|
|
459
|
+
principleId: selectedPrincipleId,
|
|
460
|
+
ruleId: parsedArtificer.ruleId,
|
|
461
|
+
sessionId: selectedSessionId,
|
|
462
|
+
sourceSnapshotRef: artifact.sourceSnapshotRef,
|
|
463
|
+
sourcePainIds: lineage.sourcePainIds,
|
|
464
|
+
sourceGateBlockIds: lineage.sourceGateBlockIds,
|
|
465
|
+
storagePath: assetRoot,
|
|
466
|
+
implementationId,
|
|
467
|
+
createdAt: now,
|
|
468
|
+
});
|
|
469
|
+
refreshPrincipleLifecycle(workspaceDir, stateDir);
|
|
470
|
+
return {
|
|
471
|
+
status: 'persisted_candidate',
|
|
472
|
+
ruleResolution: {
|
|
473
|
+
status: 'selected',
|
|
474
|
+
ruleId: parsedArtificer.ruleId,
|
|
475
|
+
reason: 'evidence-winner',
|
|
476
|
+
scores: [],
|
|
477
|
+
},
|
|
478
|
+
validationFailures: [],
|
|
479
|
+
implementationId,
|
|
480
|
+
artifactId,
|
|
481
|
+
ruleId: parsedArtificer.ruleId,
|
|
482
|
+
persistedPath: assetRoot,
|
|
483
|
+
};
|
|
484
|
+
} catch (error: unknown) {
|
|
485
|
+
deleteImplementationAssetDir(stateDir, implementationId);
|
|
486
|
+
try {
|
|
487
|
+
deleteImplementation(stateDir, implementationId);
|
|
488
|
+
} catch {
|
|
489
|
+
// Best effort cleanup to avoid leaving a half-created candidate discoverable.
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
status: 'validation_failed',
|
|
493
|
+
reason: 'persistence_failed',
|
|
494
|
+
ruleResolution: {
|
|
495
|
+
status: 'selected',
|
|
496
|
+
ruleId: parsedArtificer.ruleId,
|
|
497
|
+
reason: 'evidence-winner',
|
|
498
|
+
scores: [],
|
|
499
|
+
},
|
|
500
|
+
validationFailures: [String(error)],
|
|
501
|
+
ruleId: parsedArtificer.ruleId,
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* eslint-disable @typescript-eslint/max-params -- Reason: Function signature requires all parameters for type-safe candidate persistence */
|
|
507
|
+
function maybePersistArtificerCandidate(
|
|
508
|
+
workspaceDir: string,
|
|
509
|
+
stateDir: string,
|
|
510
|
+
selectedPrincipleId: string,
|
|
511
|
+
selectedSessionId: string,
|
|
512
|
+
snapshot: NocturnalSessionSnapshot,
|
|
513
|
+
artifact: NocturnalArtifact,
|
|
514
|
+
options: NocturnalServiceOptions
|
|
515
|
+
): NocturnalArtificerDiagnostics {
|
|
516
|
+
const ruleResolution = resolveArtificerTargetRule(
|
|
517
|
+
stateDir,
|
|
518
|
+
selectedPrincipleId,
|
|
519
|
+
snapshot
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
if (ruleResolution.status !== 'selected') {
|
|
523
|
+
return {
|
|
524
|
+
status: 'skipped',
|
|
525
|
+
reason: 'no_deterministic_rule',
|
|
526
|
+
ruleResolution,
|
|
527
|
+
validationFailures: [],
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// #219: Detect fallback data source and warn about potential signal inaccuracy
|
|
532
|
+
const validationFailures: string[] = [];
|
|
533
|
+
if (snapshot._dataSource === 'pain_context_fallback') {
|
|
534
|
+
validationFailures.push('fallback_snapshot: stats derived from pain context only (trajectory extractor failed) - signal counts may be undercounted');
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (!shouldRunArtificer(snapshot, ruleResolution)) {
|
|
538
|
+
return {
|
|
539
|
+
status: 'skipped',
|
|
540
|
+
reason: 'insufficient_signal_density',
|
|
541
|
+
ruleResolution,
|
|
542
|
+
validationFailures,
|
|
543
|
+
ruleId: ruleResolution.ruleId,
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (!artifact.betterDecision || !artifact.rationale) {
|
|
548
|
+
return {
|
|
549
|
+
status: 'skipped',
|
|
550
|
+
reason: 'missing_scribe_input',
|
|
551
|
+
ruleResolution,
|
|
552
|
+
validationFailures: [],
|
|
553
|
+
ruleId: ruleResolution.ruleId,
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const sourcePainIds = buildPainRefs(snapshot);
|
|
558
|
+
const sourceGateBlockIds = buildGateBlockRefs(snapshot);
|
|
559
|
+
const parsedArtificer =
|
|
560
|
+
options.artificerOutputOverride !== undefined
|
|
561
|
+
? parseArtificerOutput(options.artificerOutputOverride)
|
|
562
|
+
: buildDefaultArtificerOutput(
|
|
563
|
+
ruleResolution.ruleId,
|
|
564
|
+
artifact,
|
|
565
|
+
artifact.sourceSnapshotRef,
|
|
566
|
+
sourcePainIds,
|
|
567
|
+
sourceGateBlockIds
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
if (!parsedArtificer) {
|
|
571
|
+
return {
|
|
572
|
+
status: 'validation_failed',
|
|
573
|
+
reason: 'parse_failed',
|
|
574
|
+
ruleResolution,
|
|
575
|
+
validationFailures: ['Artificer output could not be parsed.'],
|
|
576
|
+
ruleId: ruleResolution.ruleId,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (parsedArtificer.ruleId !== ruleResolution.ruleId) {
|
|
581
|
+
return {
|
|
582
|
+
status: 'validation_failed',
|
|
583
|
+
reason: 'rule_mismatch',
|
|
584
|
+
ruleResolution,
|
|
585
|
+
validationFailures: [
|
|
586
|
+
`Resolved rule ${ruleResolution.ruleId} did not match candidate rule ${parsedArtificer.ruleId}.`,
|
|
587
|
+
],
|
|
588
|
+
ruleId: ruleResolution.ruleId,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const validation = validateRuleImplementationCandidate(parsedArtificer.candidateSource);
|
|
593
|
+
if (!validation.passed) {
|
|
594
|
+
return {
|
|
595
|
+
status: 'validation_failed',
|
|
596
|
+
reason: 'validator_rejected',
|
|
597
|
+
ruleResolution,
|
|
598
|
+
validationFailures: validation.failures.map((failure) => failure.message),
|
|
599
|
+
ruleId: ruleResolution.ruleId,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const persisted = persistCodeCandidate(
|
|
604
|
+
workspaceDir,
|
|
605
|
+
stateDir,
|
|
606
|
+
artifact,
|
|
607
|
+
selectedPrincipleId,
|
|
608
|
+
selectedSessionId,
|
|
609
|
+
parsedArtificer
|
|
610
|
+
);
|
|
611
|
+
return {
|
|
612
|
+
...persisted,
|
|
613
|
+
ruleResolution,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
286
617
|
// ---------------------------------------------------------------------------
|
|
287
618
|
// Main Orchestrator
|
|
288
619
|
// ---------------------------------------------------------------------------
|
|
@@ -320,6 +651,11 @@ export function executeNocturnalReflection(
|
|
|
320
651
|
arbiterResult: null,
|
|
321
652
|
executabilityResult: null,
|
|
322
653
|
persisted: false,
|
|
654
|
+
artificer: {
|
|
655
|
+
status: 'skipped',
|
|
656
|
+
ruleResolution: null,
|
|
657
|
+
validationFailures: [],
|
|
658
|
+
},
|
|
323
659
|
};
|
|
324
660
|
|
|
325
661
|
// -------------------------------------------------------------------------
|
|
@@ -407,10 +743,11 @@ export function executeNocturnalReflection(
|
|
|
407
743
|
// -------------------------------------------------------------------------
|
|
408
744
|
// Step 5: Artifact generation (Trinity or single-reflector)
|
|
409
745
|
// -------------------------------------------------------------------------
|
|
746
|
+
// eslint-disable-next-line no-useless-assignment -- Reason: initial value unused due to immediate reassignment in all branches
|
|
410
747
|
let trinityArtifact: TrinityDraftArtifact | null = null;
|
|
411
748
|
let trinityResult: TrinityResult | null = null;
|
|
749
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all branches before use at line 884
|
|
412
750
|
let rawJson: string;
|
|
413
|
-
let chainModeUsed: 'trinity' | 'single-reflector' = 'single-reflector';
|
|
414
751
|
|
|
415
752
|
if (options.skipReflector) {
|
|
416
753
|
// Caller provided explicit artifact — used for testing arbiter/executability
|
|
@@ -430,7 +767,6 @@ export function executeNocturnalReflection(
|
|
|
430
767
|
diagnostics.trinityAttempted = true;
|
|
431
768
|
diagnostics.trinityResult = trinityResult;
|
|
432
769
|
diagnostics.chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
433
|
-
chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
434
770
|
|
|
435
771
|
if (!trinityResult.success) {
|
|
436
772
|
// Trinity failed — fail closed (same semantics as production)
|
|
@@ -457,7 +793,7 @@ export function executeNocturnalReflection(
|
|
|
457
793
|
// Validate Trinity draft
|
|
458
794
|
const draftValidation = validateTrinityDraft(trinityResult.artifact);
|
|
459
795
|
if (!draftValidation.valid) {
|
|
460
|
-
const failures = draftValidation
|
|
796
|
+
const {failures} = draftValidation;
|
|
461
797
|
void recordRunEnd(stateDir, 'failed', { reason: `Trinity draft invalid: ${failures.join('; ')}` }).catch((err) => {
|
|
462
798
|
console.warn(`[nocturnal-service] Failed to record run end: ${String(err)}`);
|
|
463
799
|
});
|
|
@@ -477,7 +813,7 @@ export function executeNocturnalReflection(
|
|
|
477
813
|
diagnostics,
|
|
478
814
|
};
|
|
479
815
|
}
|
|
480
|
-
trinityArtifact = trinityResult.artifact!;
|
|
816
|
+
trinityArtifact = trinityResult.artifact!; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: artifact is validated by validateTrinityDraft which returns valid: true when artifact exists
|
|
481
817
|
// Convert Trinity draft to arbiter-compatible artifact
|
|
482
818
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
483
819
|
rawJson = JSON.stringify(artifactData);
|
|
@@ -502,14 +838,13 @@ export function executeNocturnalReflection(
|
|
|
502
838
|
trinityResult = runTrinity({ snapshot, principleId: selectedPrincipleId, config: effectiveConfig });
|
|
503
839
|
diagnostics.trinityResult = trinityResult;
|
|
504
840
|
diagnostics.chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
505
|
-
chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
506
841
|
|
|
507
842
|
if (trinityResult.success) {
|
|
508
843
|
// Validate Trinity draft
|
|
509
844
|
const draftValidation = validateTrinityDraft(trinityResult.artifact);
|
|
510
845
|
if (!draftValidation.valid) {
|
|
511
846
|
// Trinity draft invalid — fail closed
|
|
512
|
-
const failures = draftValidation
|
|
847
|
+
const {failures} = draftValidation;
|
|
513
848
|
void recordRunEnd(stateDir, 'failed', { reason: `Trinity draft invalid: ${failures.join('; ')}` }).catch((err) => {
|
|
514
849
|
console.warn(`[nocturnal-service] Failed to record run end: ${String(err)}`);
|
|
515
850
|
});
|
|
@@ -529,7 +864,7 @@ export function executeNocturnalReflection(
|
|
|
529
864
|
diagnostics,
|
|
530
865
|
};
|
|
531
866
|
}
|
|
532
|
-
trinityArtifact = trinityResult.artifact!;
|
|
867
|
+
trinityArtifact = trinityResult.artifact!; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: artifact is validated by validateTrinityDraft which returns valid: true when artifact exists
|
|
533
868
|
// Convert Trinity draft to arbiter-compatible artifact
|
|
534
869
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
535
870
|
rawJson = JSON.stringify(artifactData);
|
|
@@ -631,6 +966,7 @@ export function executeNocturnalReflection(
|
|
|
631
966
|
boundedAction: execResult.boundedAction,
|
|
632
967
|
};
|
|
633
968
|
|
|
969
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in try, catch has early return
|
|
634
970
|
let persistedPath: string;
|
|
635
971
|
try {
|
|
636
972
|
persistedPath = persistArtifact(workspaceDir, artifactWithBoundedAction);
|
|
@@ -663,6 +999,34 @@ export function executeNocturnalReflection(
|
|
|
663
999
|
console.warn(`[nocturnal-service] Failed to register sample in dataset registry: ${String(err)}`);
|
|
664
1000
|
}
|
|
665
1001
|
|
|
1002
|
+
try {
|
|
1003
|
+
appendArtifactLineageRecord(workspaceDir, {
|
|
1004
|
+
artifactKind: 'behavioral-sample',
|
|
1005
|
+
artifactId: arbiterResult.artifact.artifactId,
|
|
1006
|
+
principleId: selectedPrincipleId,
|
|
1007
|
+
ruleId: null,
|
|
1008
|
+
sessionId: selectedSessionId,
|
|
1009
|
+
sourceSnapshotRef: arbiterResult.artifact.sourceSnapshotRef,
|
|
1010
|
+
sourcePainIds: buildPainRefs(snapshot),
|
|
1011
|
+
sourceGateBlockIds: buildGateBlockRefs(snapshot),
|
|
1012
|
+
storagePath: persistedPath,
|
|
1013
|
+
implementationId: null,
|
|
1014
|
+
createdAt: arbiterResult.artifact.createdAt,
|
|
1015
|
+
});
|
|
1016
|
+
} catch (err) {
|
|
1017
|
+
console.warn(`[nocturnal-service] Failed to append behavioral artifact lineage: ${String(err)}`);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
diagnostics.artificer = maybePersistArtificerCandidate(
|
|
1021
|
+
workspaceDir,
|
|
1022
|
+
stateDir,
|
|
1023
|
+
selectedPrincipleId,
|
|
1024
|
+
selectedSessionId,
|
|
1025
|
+
snapshot,
|
|
1026
|
+
arbiterResult.artifact,
|
|
1027
|
+
options
|
|
1028
|
+
);
|
|
1029
|
+
|
|
666
1030
|
// -------------------------------------------------------------------------
|
|
667
1031
|
// Step 9: Record run success
|
|
668
1032
|
// -------------------------------------------------------------------------
|
|
@@ -726,6 +1090,7 @@ export async function executeNocturnalReflectionAsync(
|
|
|
726
1090
|
|
|
727
1091
|
// If runtime adapter is provided, use async Trinity path
|
|
728
1092
|
if (options.runtimeAdapter) {
|
|
1093
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define -- Reason: mutual recursion between helper functions - reordering would break logical grouping
|
|
729
1094
|
return executeNocturnalReflectionWithAdapter(workspaceDir, stateDir, options);
|
|
730
1095
|
}
|
|
731
1096
|
|
|
@@ -752,6 +1117,11 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
752
1117
|
arbiterResult: null,
|
|
753
1118
|
executabilityResult: null,
|
|
754
1119
|
persisted: false,
|
|
1120
|
+
artificer: {
|
|
1121
|
+
status: 'skipped',
|
|
1122
|
+
ruleResolution: null,
|
|
1123
|
+
validationFailures: [],
|
|
1124
|
+
},
|
|
755
1125
|
};
|
|
756
1126
|
|
|
757
1127
|
// Step 1: Pre-flight check
|
|
@@ -768,51 +1138,97 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
768
1138
|
return { success: false, noTargetSelected: false, validationFailed: false, validationFailures: [], diagnostics };
|
|
769
1139
|
}
|
|
770
1140
|
|
|
771
|
-
// Step 2: Target selection
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1141
|
+
// Step 2: Target selection (or use override to skip)
|
|
1142
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- Reason: assigned immediately in all branches before use
|
|
1143
|
+
let selectedPrincipleId: string | undefined;
|
|
1144
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- Reason: assigned immediately in all branches before use
|
|
1145
|
+
let selectedSessionId: string | undefined;
|
|
1146
|
+
// eslint-disable-next-line no-useless-assignment -- Reason: initial value unused due to immediate reassignment in all branches
|
|
1147
|
+
let snapshot: NocturnalSessionSnapshot | null = null;
|
|
1148
|
+
|
|
1149
|
+
if (options.principleIdOverride && options.snapshotOverride) {
|
|
1150
|
+
// Skip Selector: use provided principleId and snapshot directly
|
|
1151
|
+
selectedPrincipleId = options.principleIdOverride;
|
|
1152
|
+
selectedSessionId = options.snapshotOverride.sessionId;
|
|
1153
|
+
snapshot = options.snapshotOverride;
|
|
1154
|
+
console.log(`[nocturnal-service] Using override: principleId=${selectedPrincipleId}, sessionId=${selectedSessionId}`);
|
|
1155
|
+
// Calculate violation density from snapshot stats for meaningful diagnostics
|
|
1156
|
+
const snapStats = options.snapshotOverride.stats;
|
|
1157
|
+
const totalToolCalls = snapStats?.totalToolCalls ?? 0;
|
|
1158
|
+
const failureCount = snapStats?.failureCount ?? 0;
|
|
1159
|
+
const violationDensity = totalToolCalls > 0 ? failureCount / totalToolCalls : 0;
|
|
1160
|
+
diagnostics.selection = {
|
|
1161
|
+
decision: 'selected',
|
|
1162
|
+
selectedPrincipleId,
|
|
1163
|
+
selectedSessionId,
|
|
1164
|
+
skipReason: undefined,
|
|
1165
|
+
diagnostics: {
|
|
1166
|
+
totalEvaluablePrinciples: 1, // We provided one principle via override
|
|
1167
|
+
filteredByCooldown: 0,
|
|
1168
|
+
passedPrinciples: [selectedPrincipleId],
|
|
1169
|
+
violatingSessionCount: 1, // The session we're using
|
|
1170
|
+
selectedSessionViolationDensity: violationDensity,
|
|
1171
|
+
selectedPrincipleScore: 100, // Override means high priority
|
|
1172
|
+
scoringBreakdown: { override: 100 },
|
|
1173
|
+
idleCheckPassed: true,
|
|
1174
|
+
cooldownCheckPassed: true,
|
|
1175
|
+
quotaCheckPassed: true,
|
|
1176
|
+
},
|
|
1177
|
+
};
|
|
1178
|
+
diagnostics.idle = { isIdle: true, mostRecentActivityAt: 0, idleForMs: 0, userActiveSessions: 0, abandonedSessionIds: [], trajectoryGuardrailConfirmsIdle: true, reason: 'selector skipped (override provided)' };
|
|
1179
|
+
} else {
|
|
1180
|
+
// Normal Selector path
|
|
1181
|
+
console.log(`[nocturnal-service] Step 2/7: Target selection (normal path)`);
|
|
1182
|
+
const extractor = createNocturnalTrajectoryExtractor(workspaceDir, stateDir);
|
|
1183
|
+
const selector = new NocturnalTargetSelector(workspaceDir, stateDir, extractor, {
|
|
1184
|
+
idleCheckOverride: options.idleCheckOverride,
|
|
1185
|
+
recentPainContext: options.painContext,
|
|
1186
|
+
});
|
|
777
1187
|
|
|
778
|
-
|
|
779
|
-
|
|
1188
|
+
const selection = selector.select();
|
|
1189
|
+
diagnostics.selection = selection;
|
|
1190
|
+
console.log(`[nocturnal-service] Selector result: decision=${selection.decision}, skipReason=${selection.skipReason ?? 'none'}`);
|
|
780
1191
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
1192
|
+
if (selection.decision === 'skip') {
|
|
1193
|
+
console.warn(`[nocturnal-service] Target selection skipped: ${selection.skipReason}`);
|
|
1194
|
+
return {
|
|
1195
|
+
success: false,
|
|
1196
|
+
noTargetSelected: true,
|
|
1197
|
+
skipReason: selection.skipReason,
|
|
1198
|
+
validationFailed: false,
|
|
1199
|
+
validationFailures: [],
|
|
1200
|
+
diagnostics,
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
791
1203
|
|
|
792
|
-
|
|
1204
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring -- Reason: selectedPrincipleId/selectedSessionId are reassignable outer lets - destructuring would shadow
|
|
1205
|
+
selectedPrincipleId = selection.selectedPrincipleId;
|
|
1206
|
+
// eslint-disable-next-line @typescript-eslint/prefer-destructuring -- Reason: selectedPrincipleId/selectedSessionId are reassignable outer lets - destructuring would shadow
|
|
1207
|
+
selectedSessionId = selection.selectedSessionId;
|
|
793
1208
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
1209
|
+
if (!selectedPrincipleId || !selectedSessionId) {
|
|
1210
|
+
return {
|
|
1211
|
+
success: false,
|
|
1212
|
+
noTargetSelected: true,
|
|
1213
|
+
validationFailed: false,
|
|
1214
|
+
validationFailures: [],
|
|
1215
|
+
diagnostics,
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
803
1218
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1219
|
+
snapshot = extractor.getNocturnalSessionSnapshot(selectedSessionId);
|
|
1220
|
+
if (!snapshot) {
|
|
1221
|
+
return {
|
|
1222
|
+
success: false,
|
|
1223
|
+
noTargetSelected: true,
|
|
1224
|
+
skipReason: 'insufficient_snapshot_data',
|
|
1225
|
+
validationFailed: false,
|
|
1226
|
+
validationFailures: [],
|
|
1227
|
+
diagnostics,
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
diagnostics.idle = { isIdle: true, mostRecentActivityAt: 0, idleForMs: 0, userActiveSessions: 0, abandonedSessionIds: [], trajectoryGuardrailConfirmsIdle: true, reason: 'preflight passed' };
|
|
814
1231
|
}
|
|
815
|
-
diagnostics.idle = { isIdle: true, mostRecentActivityAt: 0, idleForMs: 0, userActiveSessions: 0, abandonedSessionIds: [], trajectoryGuardrailConfirmsIdle: true, reason: 'preflight passed' };
|
|
816
1232
|
|
|
817
1233
|
// Step 3: Record run start
|
|
818
1234
|
void recordRunStart(stateDir, selectedPrincipleId).catch((err) => {
|
|
@@ -820,10 +1236,11 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
820
1236
|
});
|
|
821
1237
|
|
|
822
1238
|
// Step 4: Trinity execution via adapter (async)
|
|
1239
|
+
// eslint-disable-next-line no-useless-assignment -- Reason: initial value unused due to immediate reassignment in all branches
|
|
823
1240
|
let trinityArtifact: TrinityDraftArtifact | null = null;
|
|
824
1241
|
let trinityResult: TrinityResult | null = null;
|
|
1242
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all branches before use
|
|
825
1243
|
let rawJson: string;
|
|
826
|
-
let chainModeUsed: 'trinity' | 'single-reflector' = 'single-reflector';
|
|
827
1244
|
|
|
828
1245
|
if (options.skipReflector) {
|
|
829
1246
|
if (!options.reflectorOutputOverride) {
|
|
@@ -841,7 +1258,6 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
841
1258
|
diagnostics.trinityAttempted = true;
|
|
842
1259
|
diagnostics.trinityResult = trinityResult;
|
|
843
1260
|
diagnostics.chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
844
|
-
chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
845
1261
|
|
|
846
1262
|
if (!trinityResult.success) {
|
|
847
1263
|
const failures = trinityResult.failures.map((f) => `${f.stage}: ${f.reason}`);
|
|
@@ -851,7 +1267,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
851
1267
|
adjustThresholdsFromSignals(stateDir, { malformedRate: 1.0, arbiterRejectRate: 0.0, executabilityRejectRate: 0.0, qualityDelta: 0.0 });
|
|
852
1268
|
return { success: false, noTargetSelected: false, validationFailed: true, validationFailures: [`Trinity override failed: ${failures.join('; ')}`], snapshot, diagnostics };
|
|
853
1269
|
}
|
|
854
|
-
trinityArtifact = trinityResult.artifact!;
|
|
1270
|
+
trinityArtifact = trinityResult.artifact!; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: artifact is validated by validateTrinityDraft which returns valid: true when artifact exists
|
|
855
1271
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
856
1272
|
rawJson = JSON.stringify(artifactData);
|
|
857
1273
|
} else {
|
|
@@ -867,19 +1283,18 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
867
1283
|
trinityResult = await runTrinityAsync({ snapshot, principleId: selectedPrincipleId, config: trinityConfig });
|
|
868
1284
|
diagnostics.trinityResult = trinityResult;
|
|
869
1285
|
diagnostics.chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
870
|
-
chainModeUsed = trinityResult.success ? 'trinity' : 'single-reflector';
|
|
871
1286
|
|
|
872
1287
|
if (trinityResult.success) {
|
|
873
1288
|
const draftValidation = validateTrinityDraft(trinityResult.artifact);
|
|
874
1289
|
if (!draftValidation.valid) {
|
|
875
|
-
const failures = draftValidation
|
|
1290
|
+
const {failures} = draftValidation;
|
|
876
1291
|
void recordRunEnd(stateDir, 'failed', { reason: `Trinity draft invalid: ${failures.join('; ')}` }).catch((err) => {
|
|
877
1292
|
console.warn(`[nocturnal-service] Failed to record run end: ${String(err)}`);
|
|
878
1293
|
});
|
|
879
1294
|
adjustThresholdsFromSignals(stateDir, { malformedRate: 1.0, arbiterRejectRate: 0.0, executabilityRejectRate: 0.0, qualityDelta: 0.0 });
|
|
880
1295
|
return { success: false, noTargetSelected: false, validationFailed: true, validationFailures: failures, snapshot, diagnostics };
|
|
881
1296
|
}
|
|
882
|
-
trinityArtifact = trinityResult.artifact!;
|
|
1297
|
+
trinityArtifact = trinityResult.artifact!; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: artifact is validated by validateTrinityDraft which returns valid: true when artifact exists
|
|
883
1298
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
884
1299
|
rawJson = JSON.stringify(artifactData);
|
|
885
1300
|
} else {
|
|
@@ -929,6 +1344,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
929
1344
|
|
|
930
1345
|
// Step 7: Persist artifact
|
|
931
1346
|
const artifactWithBoundedAction = { ...arbiterResult.artifact, boundedAction: execResult.boundedAction };
|
|
1347
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in try, catch has early return
|
|
932
1348
|
let persistedPath: string;
|
|
933
1349
|
try {
|
|
934
1350
|
persistedPath = persistArtifact(workspaceDir, artifactWithBoundedAction);
|
|
@@ -948,6 +1364,34 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
948
1364
|
console.warn(`[nocturnal-service] Failed to register sample in dataset registry: ${String(err)}`);
|
|
949
1365
|
}
|
|
950
1366
|
|
|
1367
|
+
try {
|
|
1368
|
+
appendArtifactLineageRecord(workspaceDir, {
|
|
1369
|
+
artifactKind: 'behavioral-sample',
|
|
1370
|
+
artifactId: arbiterResult.artifact.artifactId,
|
|
1371
|
+
principleId: selectedPrincipleId,
|
|
1372
|
+
ruleId: null,
|
|
1373
|
+
sessionId: selectedSessionId,
|
|
1374
|
+
sourceSnapshotRef: arbiterResult.artifact.sourceSnapshotRef,
|
|
1375
|
+
sourcePainIds: buildPainRefs(snapshot),
|
|
1376
|
+
sourceGateBlockIds: buildGateBlockRefs(snapshot),
|
|
1377
|
+
storagePath: persistedPath,
|
|
1378
|
+
implementationId: null,
|
|
1379
|
+
createdAt: arbiterResult.artifact.createdAt,
|
|
1380
|
+
});
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
console.warn(`[nocturnal-service] Failed to append behavioral artifact lineage: ${String(err)}`);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
diagnostics.artificer = maybePersistArtificerCandidate(
|
|
1386
|
+
workspaceDir,
|
|
1387
|
+
stateDir,
|
|
1388
|
+
selectedPrincipleId,
|
|
1389
|
+
selectedSessionId,
|
|
1390
|
+
snapshot,
|
|
1391
|
+
arbiterResult.artifact,
|
|
1392
|
+
options
|
|
1393
|
+
);
|
|
1394
|
+
|
|
951
1395
|
// Step 9: Record run success
|
|
952
1396
|
void recordRunEnd(stateDir, 'success', { sampleCount: 1 }).catch((err) => {
|
|
953
1397
|
console.warn(`[nocturnal-service] Failed to record run end (success): ${String(err)}`);
|
|
@@ -982,9 +1426,9 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
982
1426
|
*/
|
|
983
1427
|
export function listApprovedNocturnalArtifacts(
|
|
984
1428
|
workspaceDir: string
|
|
985
|
-
):
|
|
1429
|
+
): (NocturnalArtifact & { persistedAt: string; boundedAction?: BoundedAction })[] {
|
|
986
1430
|
const samplePaths = NocturnalPathResolver.listApprovedSamples(workspaceDir);
|
|
987
|
-
const artifacts:
|
|
1431
|
+
const artifacts: (NocturnalArtifact & { persistedAt: string; boundedAction?: BoundedAction })[] = [];
|
|
988
1432
|
|
|
989
1433
|
for (const samplePath of samplePaths) {
|
|
990
1434
|
try {
|