scene-capability-engine 3.6.64 → 3.6.67
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 +17 -6
- package/README.zh.md +18 -6
- package/bin/scene-capability-engine.js +4 -0
- package/docs/README.md +2 -2
- package/docs/command-reference.md +385 -8
- package/docs/document-governance.md +3 -2
- package/docs/integration-modes.md +62 -478
- package/docs/integration-philosophy.md +56 -263
- package/docs/magicball-cli-invocation-examples.md +1 -0
- package/docs/magicball-project-portfolio-contract.md +125 -4
- package/docs/project-management/README.md +14 -0
- package/docs/project-management/assurance/backup.md +3 -0
- package/docs/project-management/assurance/config.md +3 -0
- package/docs/project-management/assurance/evidence/README.md +3 -0
- package/docs/project-management/assurance/incidents/README.md +3 -0
- package/docs/project-management/assurance/logs.md +3 -0
- package/docs/project-management/assurance/overview.md +3 -0
- package/docs/project-management/assurance/recovery/README.md +3 -0
- package/docs/project-management/assurance/resource.md +3 -0
- package/docs/project-management/assurance/runbooks/README.md +3 -0
- package/docs/project-management/delivery/acceptance/README.md +3 -0
- package/docs/project-management/delivery/acceptance/evidence/README.md +3 -0
- package/docs/project-management/delivery/acceptance/exceptions/README.md +3 -0
- package/docs/project-management/delivery/acceptance/reports/README.md +3 -0
- package/docs/project-management/delivery/documents/changes.md +3 -0
- package/docs/project-management/delivery/documents/issues.md +3 -0
- package/docs/project-management/delivery/documents/overview.md +3 -0
- package/docs/project-management/delivery/documents/planning.md +3 -0
- package/docs/project-management/delivery/documents/requirements.md +3 -0
- package/docs/project-management/delivery/documents/tracking.md +3 -0
- package/docs/project-management/delivery/handoffs/README.md +3 -0
- package/docs/project-management/delivery/handoffs/evidence/README.md +3 -0
- package/docs/project-management/delivery/handoffs/records/README.md +3 -0
- package/docs/project-management/delivery/overview.md +10 -0
- package/docs/project-management/delivery/releases/README.md +3 -0
- package/docs/project-management/delivery/releases/baselines/README.md +3 -0
- package/docs/project-management/delivery/releases/evidence/README.md +3 -0
- package/docs/project-management/delivery/tables/changes.md +3 -0
- package/docs/project-management/delivery/tables/issues.md +3 -0
- package/docs/project-management/delivery/tables/planning.md +3 -0
- package/docs/project-management/delivery/tables/requirements.md +3 -0
- package/docs/project-management/delivery/tables/tracking.md +3 -0
- package/docs/project-management/environment/agent-discovery.md +3 -0
- package/docs/project-management/environment/development.md +3 -0
- package/docs/project-management/environment/overview.md +10 -0
- package/docs/project-management/environment/testing.md +3 -0
- package/docs/project-management/environment/version-alignment.md +3 -0
- package/docs/quick-start-with-ai-tools.md +68 -308
- package/docs/releases/README.md +3 -0
- package/docs/releases/v3.6.65.md +25 -0
- package/docs/releases/v3.6.66.md +23 -0
- package/docs/releases/v3.6.67.md +23 -0
- package/docs/steering-governance.md +64 -2
- package/docs/zh/README.md +2 -2
- package/docs/zh/releases/README.md +3 -0
- package/docs/zh/releases/v3.6.65.md +25 -0
- package/docs/zh/releases/v3.6.66.md +23 -0
- package/docs/zh/releases/v3.6.67.md +23 -0
- package/lib/commands/adopt.js +24 -0
- package/lib/commands/native.js +158 -0
- package/lib/commands/project.js +96 -0
- package/lib/commands/semantic.js +1459 -0
- package/lib/commands/session.js +74 -3
- package/lib/commands/spec-bootstrap.js +10 -1
- package/lib/commands/spec-gate.js +10 -1
- package/lib/commands/spec-pipeline.js +10 -1
- package/lib/commands/studio.js +405 -30
- package/lib/commands/task.js +141 -7
- package/lib/governance/supreme-principles.js +530 -0
- package/lib/problem/problem-evaluator.js +4 -0
- package/lib/project/candidate-inspection-service.js +24 -1
- package/lib/project/portfolio-projection-service.js +315 -5
- package/lib/project/project-channel-output.js +94 -0
- package/lib/project/project-channel-projection.js +181 -0
- package/lib/project/root-onboarding-service.js +107 -7
- package/lib/project/semantic-shared-source-projection.js +150 -0
- package/lib/project/supervision-action-model.js +277 -0
- package/lib/project/supervision-projection-service.js +305 -5
- package/lib/project/target-resolution-service.js +70 -5
- package/lib/project/visibility-policy.js +93 -0
- package/lib/runtime/multi-spec-scene-session.js +8 -1
- package/lib/runtime/project-channel-context-store.js +387 -0
- package/lib/runtime/project-channel-context.js +406 -0
- package/lib/runtime/scene-session-binding.js +46 -0
- package/lib/runtime/session-store.js +186 -0
- package/lib/runtime/steering-contract.js +7 -1
- package/lib/semantic/archive-report.js +283 -0
- package/lib/semantic/archive-routing.js +67 -0
- package/lib/semantic/backflow-report.js +245 -0
- package/lib/semantic/capability-contract.js +30 -0
- package/lib/semantic/delta-export.js +145 -0
- package/lib/semantic/interaction-observer.js +254 -0
- package/lib/semantic/kernel-loader.js +881 -0
- package/lib/semantic/native-runtime.js +359 -0
- package/lib/semantic/progress-ledger.js +433 -0
- package/lib/semantic/replay-evaluator.js +382 -0
- package/lib/semantic/shared-publication.js +592 -0
- package/lib/semantic/shared-source-config.js +183 -0
- package/lib/semantic/shared-source-connect.js +139 -0
- package/lib/semantic/shared-source-discovery.js +98 -0
- package/lib/semantic/shared-sync-export.js +413 -0
- package/lib/semantic/shared-sync-intake.js +592 -0
- package/lib/semantic/shared-sync-merge.js +547 -0
- package/lib/semantic/shared-sync-release.js +463 -0
- package/lib/semantic/supreme-intent-report.js +300 -0
- package/lib/state/sce-state-store.js +1360 -0
- package/lib/steering/context-sync-manager.js +276 -25
- package/lib/studio/spec-intake-governor.js +39 -3
- package/lib/studio/task-envelope.js +35 -2
- package/lib/workspace/takeover-baseline.js +342 -83
- package/package.json +7 -2
- package/scripts/agent-governance-baseline-audit.js +395 -0
- package/scripts/clarification-first-audit.js +9 -9
- package/scripts/deprecated-entry-audit.js +240 -0
- package/scripts/release-doc-version-audit.js +24 -0
- package/scripts/release-posture-report.js +262 -0
- package/template/.sce/README.md +62 -228
- package/template/.sce/config/semantic-shared-sources.json +5 -0
- package/template/.sce/config/supreme-principles-policy.json +105 -0
- package/template/.sce/config/takeover-baseline.json +7 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +23 -63
- package/template/.sce/steering/CURRENT_CONTEXT.md +4 -0
- package/template/.sce/steering/RULES_GUIDE.md +17 -9
- package/template/README.md +32 -96
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { getSceStateStore } = require('../state/sce-state-store');
|
|
4
|
+
const { buildSemanticArchiveDecision } = require('./archive-routing');
|
|
5
|
+
const {
|
|
6
|
+
resolveTargetLibrary,
|
|
7
|
+
buildCapabilityId
|
|
8
|
+
} = require('./capability-contract');
|
|
9
|
+
|
|
10
|
+
function normalizeString(value) {
|
|
11
|
+
if (typeof value !== 'string') {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
return value.trim();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeInteger(value, fallback = 0) {
|
|
18
|
+
const parsed = Number.parseInt(`${value}`, 10);
|
|
19
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
20
|
+
return fallback;
|
|
21
|
+
}
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeStringArray(value, fallback = []) {
|
|
26
|
+
if (!Array.isArray(value)) {
|
|
27
|
+
return [...fallback];
|
|
28
|
+
}
|
|
29
|
+
return value
|
|
30
|
+
.map((item) => normalizeString(item))
|
|
31
|
+
.filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildDeltaEntry(lesson = {}) {
|
|
35
|
+
const evidence = lesson.evidence && typeof lesson.evidence === 'object' ? lesson.evidence : {};
|
|
36
|
+
const promotion = evidence.promotion && typeof evidence.promotion === 'object' ? evidence.promotion : {};
|
|
37
|
+
const metadata = lesson.metadata && typeof lesson.metadata === 'object' ? lesson.metadata : {};
|
|
38
|
+
const publish = metadata.publish && typeof metadata.publish === 'object' ? metadata.publish : {};
|
|
39
|
+
const archive = metadata.archive && typeof metadata.archive === 'object'
|
|
40
|
+
? metadata.archive
|
|
41
|
+
: buildSemanticArchiveDecision(lesson);
|
|
42
|
+
return {
|
|
43
|
+
capability_id: buildCapabilityId(lesson),
|
|
44
|
+
lesson_id: lesson.lesson_id,
|
|
45
|
+
target_library: normalizeString(archive.target_library) || resolveTargetLibrary(lesson),
|
|
46
|
+
scene_id: normalizeString(lesson.scene_id) || null,
|
|
47
|
+
spec_id: normalizeString(lesson.spec_id) || null,
|
|
48
|
+
lesson_type: normalizeString(lesson.lesson_type) || null,
|
|
49
|
+
title: normalizeString(lesson.title) || null,
|
|
50
|
+
summary: normalizeString(lesson.summary) || null,
|
|
51
|
+
heuristic: normalizeString(lesson.heuristic) || null,
|
|
52
|
+
confidence: typeof lesson.confidence === 'number' ? lesson.confidence : null,
|
|
53
|
+
status: normalizeString(lesson.status) || null,
|
|
54
|
+
lineage: {
|
|
55
|
+
observation_ids: normalizeStringArray([
|
|
56
|
+
evidence.observation_id
|
|
57
|
+
], []),
|
|
58
|
+
evaluation_run_id: normalizeString(promotion.evaluation_run_id) || null
|
|
59
|
+
},
|
|
60
|
+
publication: {
|
|
61
|
+
consent_model: normalizeString(publish.consent_model) || 'adopt-implied',
|
|
62
|
+
publish_required: publish.publish_required === true,
|
|
63
|
+
publish_state: normalizeString(publish.publish_state) || 'pending',
|
|
64
|
+
queued_at: normalizeString(publish.queued_at) || null
|
|
65
|
+
},
|
|
66
|
+
archive,
|
|
67
|
+
sanitized: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveDefaultSemanticDeltaOutFile(specId = '') {
|
|
72
|
+
const normalizedSpecId = normalizeString(specId);
|
|
73
|
+
if (!normalizedSpecId) {
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
return `.sce/specs/${normalizedSpecId}/deltas/latest.json`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function exportSemanticLibraryDelta(options = {}, dependencies = {}) {
|
|
80
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
81
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
82
|
+
const store = dependencies.stateStore || getSceStateStore(projectPath, {
|
|
83
|
+
fileSystem,
|
|
84
|
+
env: dependencies.env,
|
|
85
|
+
sqliteModule: dependencies.sqliteModule,
|
|
86
|
+
noCache: dependencies.noCache === true
|
|
87
|
+
});
|
|
88
|
+
const projectId = normalizeString(options.project_id || options.projectId);
|
|
89
|
+
const specId = normalizeString(options.spec_id || options.specId);
|
|
90
|
+
const lessonId = normalizeString(options.lesson_id || options.lessonId);
|
|
91
|
+
const capabilityId = normalizeString(options.capability_id || options.capabilityId);
|
|
92
|
+
const limit = normalizeInteger(options.limit, 100);
|
|
93
|
+
|
|
94
|
+
let lessons = await store.listSemanticLessonCandidates({
|
|
95
|
+
project_id: projectId,
|
|
96
|
+
limit
|
|
97
|
+
});
|
|
98
|
+
lessons = Array.isArray(lessons) ? lessons : [];
|
|
99
|
+
lessons = lessons.filter((item) => {
|
|
100
|
+
if (normalizeString(item.status) !== 'publish_pending') {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (specId && normalizeString(item.spec_id) !== specId) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (lessonId && normalizeString(item.lesson_id) !== lessonId) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (capabilityId && buildCapabilityId(item) !== capabilityId) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const payload = {
|
|
116
|
+
mode: 'semantic-delta-export',
|
|
117
|
+
success: true,
|
|
118
|
+
generated_at: new Date().toISOString(),
|
|
119
|
+
project_id: projectId || null,
|
|
120
|
+
spec_id: specId || null,
|
|
121
|
+
total: lessons.length,
|
|
122
|
+
entries: lessons.map((item) => buildDeltaEntry(item))
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const outFile = normalizeString(options.out_file || options.outFile)
|
|
126
|
+
|| resolveDefaultSemanticDeltaOutFile(specId);
|
|
127
|
+
if (outFile) {
|
|
128
|
+
const absolutePath = path.isAbsolute(outFile)
|
|
129
|
+
? outFile
|
|
130
|
+
: path.join(projectPath, outFile);
|
|
131
|
+
await fileSystem.ensureDir(path.dirname(absolutePath));
|
|
132
|
+
await fileSystem.writeJson(absolutePath, payload, { spaces: 2 });
|
|
133
|
+
payload.out_file = path.relative(projectPath, absolutePath).replace(/\\/g, '/');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return payload;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = {
|
|
140
|
+
resolveTargetLibrary,
|
|
141
|
+
buildCapabilityId,
|
|
142
|
+
buildDeltaEntry,
|
|
143
|
+
resolveDefaultSemanticDeltaOutFile,
|
|
144
|
+
exportSemanticLibraryDelta
|
|
145
|
+
};
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
const { getSceStateStore } = require('../state/sce-state-store');
|
|
3
|
+
const { buildSemanticArchiveDecision } = require('./archive-routing');
|
|
4
|
+
|
|
5
|
+
function normalizeString(value) {
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
return '';
|
|
8
|
+
}
|
|
9
|
+
return value.trim();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeTextPreview(value, fallback = '') {
|
|
13
|
+
const normalized = normalizeString(value || fallback);
|
|
14
|
+
if (!normalized) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
return normalized.replace(/\s+/g, ' ').slice(0, 240);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeSignal(value, allowed, fallback) {
|
|
21
|
+
const normalized = normalizeString(value).toLowerCase();
|
|
22
|
+
if (allowed.has(normalized)) {
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function inferIntent(payload = {}) {
|
|
29
|
+
const explicit = normalizeString(payload.intent);
|
|
30
|
+
if (explicit) {
|
|
31
|
+
return explicit;
|
|
32
|
+
}
|
|
33
|
+
const text = normalizeString(payload.text || payload.summary || '');
|
|
34
|
+
if (!text) {
|
|
35
|
+
return 'unknown';
|
|
36
|
+
}
|
|
37
|
+
const lowered = text.toLowerCase();
|
|
38
|
+
if (/(fix|repair|debug|trace|定位|修复)/.test(lowered)) {
|
|
39
|
+
return 'debug-or-repair';
|
|
40
|
+
}
|
|
41
|
+
if (/(plan|design|spec|requirements|tasks|方案|设计)/.test(lowered)) {
|
|
42
|
+
return 'planning';
|
|
43
|
+
}
|
|
44
|
+
if (/(test|verify|validation|回归|验证)/.test(lowered)) {
|
|
45
|
+
return 'verification';
|
|
46
|
+
}
|
|
47
|
+
if (/(explain|why|how|what|说明|解释|为什么|如何)/.test(lowered)) {
|
|
48
|
+
return 'analysis';
|
|
49
|
+
}
|
|
50
|
+
return 'general';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function inferOutcome(payload = {}) {
|
|
54
|
+
const explicit = normalizeString(payload.outcome);
|
|
55
|
+
if (explicit) {
|
|
56
|
+
return explicit;
|
|
57
|
+
}
|
|
58
|
+
const lowered = normalizeString(payload.text || payload.summary || '').toLowerCase();
|
|
59
|
+
if (/(failed|error|blocked|timeout|exception|失败|报错|阻塞)/.test(lowered)) {
|
|
60
|
+
return 'failed';
|
|
61
|
+
}
|
|
62
|
+
if (/(done|completed|success|resolved|完成|成功|已修复)/.test(lowered)) {
|
|
63
|
+
return 'succeeded';
|
|
64
|
+
}
|
|
65
|
+
return 'observed';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function inferQualitySignal(payload = {}) {
|
|
69
|
+
const explicit = normalizeString(payload.quality_signal || payload.qualitySignal);
|
|
70
|
+
if (explicit) {
|
|
71
|
+
return explicit;
|
|
72
|
+
}
|
|
73
|
+
const outcome = inferOutcome(payload);
|
|
74
|
+
if (outcome === 'failed') {
|
|
75
|
+
return 'negative';
|
|
76
|
+
}
|
|
77
|
+
if (outcome === 'succeeded') {
|
|
78
|
+
return 'positive';
|
|
79
|
+
}
|
|
80
|
+
return 'mixed';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function buildObservationSummary(payload = {}) {
|
|
84
|
+
const explicit = normalizeTextPreview(payload.summary);
|
|
85
|
+
if (explicit) {
|
|
86
|
+
return explicit;
|
|
87
|
+
}
|
|
88
|
+
return normalizeTextPreview(payload.text, `${payload.source_runtime || payload.sourceRuntime || 'runtime'} ${payload.event_kind || payload.eventKind || 'event'}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function normalizeSemanticObservation(payload = {}) {
|
|
92
|
+
const sourceRuntime = normalizeString(payload.source_runtime || payload.sourceRuntime).toLowerCase();
|
|
93
|
+
const eventKind = normalizeString(payload.event_kind || payload.eventKind).toLowerCase();
|
|
94
|
+
if (!sourceRuntime) {
|
|
95
|
+
throw new Error('source_runtime is required');
|
|
96
|
+
}
|
|
97
|
+
if (!eventKind) {
|
|
98
|
+
throw new Error('event_kind is required');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const rawPayload = payload.raw_payload && typeof payload.raw_payload === 'object'
|
|
102
|
+
? payload.raw_payload
|
|
103
|
+
: (payload.rawPayload && typeof payload.rawPayload === 'object' ? payload.rawPayload : {});
|
|
104
|
+
const text = normalizeTextPreview(payload.text || payload.message || payload.content);
|
|
105
|
+
const summary = buildObservationSummary({
|
|
106
|
+
...payload,
|
|
107
|
+
text
|
|
108
|
+
});
|
|
109
|
+
const normalized = {
|
|
110
|
+
observation_id: normalizeString(payload.observation_id || payload.observationId) || null,
|
|
111
|
+
project_id: normalizeString(payload.project_id || payload.projectId) || null,
|
|
112
|
+
channel_id: normalizeString(payload.channel_id || payload.channelId) || null,
|
|
113
|
+
session_id: normalizeString(payload.session_id || payload.sessionId) || null,
|
|
114
|
+
scene_id: normalizeString(payload.scene_id || payload.sceneId) || null,
|
|
115
|
+
spec_id: normalizeString(payload.spec_id || payload.specId) || null,
|
|
116
|
+
task_ref: normalizeString(payload.task_ref || payload.taskRef) || null,
|
|
117
|
+
source_runtime: sourceRuntime,
|
|
118
|
+
source_kind: normalizeString(payload.source_kind || payload.sourceKind) || 'embedded-host',
|
|
119
|
+
host_session_id: normalizeString(payload.host_session_id || payload.hostSessionId) || null,
|
|
120
|
+
event_kind: eventKind,
|
|
121
|
+
role: normalizeString(payload.role).toLowerCase() || null,
|
|
122
|
+
intent: inferIntent({ ...payload, text }),
|
|
123
|
+
summary,
|
|
124
|
+
outcome: normalizeSignal(inferOutcome({ ...payload, text }), new Set(['observed', 'succeeded', 'failed', 'blocked']), 'observed'),
|
|
125
|
+
quality_signal: normalizeSignal(
|
|
126
|
+
inferQualitySignal({ ...payload, text }),
|
|
127
|
+
new Set(['positive', 'negative', 'mixed', 'unknown']),
|
|
128
|
+
'mixed'
|
|
129
|
+
),
|
|
130
|
+
raw_ref: normalizeString(payload.raw_ref || payload.rawRef) || null,
|
|
131
|
+
raw_payload: {
|
|
132
|
+
text,
|
|
133
|
+
...rawPayload
|
|
134
|
+
},
|
|
135
|
+
normalized_payload: {
|
|
136
|
+
text,
|
|
137
|
+
summary,
|
|
138
|
+
role: normalizeString(payload.role).toLowerCase() || null,
|
|
139
|
+
intent: inferIntent({ ...payload, text }),
|
|
140
|
+
outcome: normalizeSignal(inferOutcome({ ...payload, text }), new Set(['observed', 'succeeded', 'failed', 'blocked']), 'observed'),
|
|
141
|
+
quality_signal: normalizeSignal(
|
|
142
|
+
inferQualitySignal({ ...payload, text }),
|
|
143
|
+
new Set(['positive', 'negative', 'mixed', 'unknown']),
|
|
144
|
+
'mixed'
|
|
145
|
+
),
|
|
146
|
+
metadata: payload.metadata && typeof payload.metadata === 'object' ? payload.metadata : {}
|
|
147
|
+
},
|
|
148
|
+
created_at: normalizeString(payload.created_at || payload.createdAt) || null,
|
|
149
|
+
updated_at: normalizeString(payload.updated_at || payload.updatedAt) || null
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return normalized;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function buildLessonFingerprint(observation = {}) {
|
|
156
|
+
const basis = JSON.stringify({
|
|
157
|
+
project_id: normalizeString(observation.project_id),
|
|
158
|
+
scene_id: normalizeString(observation.scene_id),
|
|
159
|
+
spec_id: normalizeString(observation.spec_id),
|
|
160
|
+
source_runtime: normalizeString(observation.source_runtime),
|
|
161
|
+
intent: normalizeString(observation.intent),
|
|
162
|
+
outcome: normalizeString(observation.outcome),
|
|
163
|
+
quality_signal: normalizeString(observation.quality_signal)
|
|
164
|
+
});
|
|
165
|
+
return crypto.createHash('sha1').update(basis).digest('hex').slice(0, 16);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function deriveLessonCandidate(observation = {}) {
|
|
169
|
+
const qualitySignal = normalizeString(observation.quality_signal);
|
|
170
|
+
const outcome = normalizeString(observation.outcome);
|
|
171
|
+
const shouldPromote = qualitySignal === 'positive' || qualitySignal === 'negative' || outcome === 'failed';
|
|
172
|
+
if (!shouldPromote) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const lessonType = qualitySignal === 'negative' || outcome === 'failed'
|
|
177
|
+
? 'failure-pattern'
|
|
178
|
+
: 'success-pattern';
|
|
179
|
+
const fingerprint = buildLessonFingerprint(observation);
|
|
180
|
+
const title = lessonType === 'failure-pattern'
|
|
181
|
+
? `[${observation.source_runtime}] Avoid ${observation.intent || observation.event_kind}`
|
|
182
|
+
: `[${observation.source_runtime}] Reuse ${observation.intent || observation.event_kind}`;
|
|
183
|
+
const summary = lessonType === 'failure-pattern'
|
|
184
|
+
? `Observed ${observation.intent || observation.event_kind} leading to ${outcome || 'negative outcome'} in project context.`
|
|
185
|
+
: `Observed ${observation.intent || observation.event_kind} leading to successful outcome in project context.`;
|
|
186
|
+
const heuristic = lessonType === 'failure-pattern'
|
|
187
|
+
? `When handling ${observation.intent || observation.event_kind}, add stronger verification or narrower scoping before execution.`
|
|
188
|
+
: `When handling ${observation.intent || observation.event_kind}, preserve the successful structure captured in the observation evidence.`;
|
|
189
|
+
|
|
190
|
+
const lesson = {
|
|
191
|
+
project_id: observation.project_id,
|
|
192
|
+
scene_id: observation.scene_id,
|
|
193
|
+
spec_id: observation.spec_id,
|
|
194
|
+
source_runtime: observation.source_runtime,
|
|
195
|
+
fingerprint,
|
|
196
|
+
lesson_type: lessonType,
|
|
197
|
+
title,
|
|
198
|
+
summary,
|
|
199
|
+
heuristic,
|
|
200
|
+
confidence: lessonType === 'failure-pattern' ? 0.75 : 0.7,
|
|
201
|
+
status: 'candidate',
|
|
202
|
+
evidence: {
|
|
203
|
+
observation_id: observation.observation_id,
|
|
204
|
+
task_ref: observation.task_ref,
|
|
205
|
+
quality_signal: observation.quality_signal,
|
|
206
|
+
outcome: observation.outcome
|
|
207
|
+
},
|
|
208
|
+
metadata: {
|
|
209
|
+
channel_id: observation.channel_id,
|
|
210
|
+
session_id: observation.session_id,
|
|
211
|
+
event_kind: observation.event_kind
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
return {
|
|
215
|
+
...lesson,
|
|
216
|
+
metadata: {
|
|
217
|
+
...lesson.metadata,
|
|
218
|
+
archive: buildSemanticArchiveDecision(lesson)
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function observeSemanticInteraction(payload = {}, dependencies = {}) {
|
|
224
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
225
|
+
const store = dependencies.stateStore || getSceStateStore(projectPath, {
|
|
226
|
+
fileSystem: dependencies.fileSystem,
|
|
227
|
+
env: dependencies.env,
|
|
228
|
+
sqliteModule: dependencies.sqliteModule,
|
|
229
|
+
noCache: dependencies.noCache === true
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const normalizedObservation = normalizeSemanticObservation(payload);
|
|
233
|
+
const observation = await store.appendSemanticObservation(normalizedObservation);
|
|
234
|
+
if (!observation) {
|
|
235
|
+
throw new Error('Failed to persist semantic observation');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const lessonCandidate = deriveLessonCandidate(observation);
|
|
239
|
+
const lesson = lessonCandidate
|
|
240
|
+
? await store.upsertSemanticLessonCandidate(lessonCandidate)
|
|
241
|
+
: null;
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
observation,
|
|
245
|
+
lesson_candidate: lesson
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
module.exports = {
|
|
250
|
+
normalizeSemanticObservation,
|
|
251
|
+
buildLessonFingerprint,
|
|
252
|
+
deriveLessonCandidate,
|
|
253
|
+
observeSemanticInteraction
|
|
254
|
+
};
|