scene-capability-engine 3.4.5 → 3.5.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 +40 -0
- package/README.md +31 -1
- package/README.zh.md +31 -1
- package/docs/command-reference.md +73 -7
- package/docs/images/wechat-qr.png +0 -0
- package/lib/adoption/adoption-strategy.js +2 -0
- package/lib/adoption/detection-engine.js +2 -0
- package/lib/adoption/file-classifier.js +3 -1
- package/lib/adoption/smart-orchestrator.js +2 -0
- package/lib/commands/errorbook.js +142 -2
- package/lib/commands/studio.js +569 -25
- package/lib/problem/problem-evaluator.js +431 -16
- package/lib/spec/domain-modeling.js +49 -4
- package/lib/studio/spec-intake-governor.js +992 -0
- package/lib/workspace/takeover-baseline.js +128 -4
- package/package.json +1 -1
- package/template/.sce/config/problem-closure-policy.json +18 -0
- package/template/.sce/config/problem-eval-policy.json +43 -1
- package/template/.sce/config/spec-domain-policy.json +9 -1
- package/template/.sce/config/studio-intake-policy.json +68 -0
- package/template/.sce/config/takeover-baseline.json +88 -1
- package/template/.sce/steering/CORE_PRINCIPLES.md +4 -2
|
@@ -6,6 +6,7 @@ const DEFAULT_POLICY_PATH = '.sce/config/problem-eval-policy.json';
|
|
|
6
6
|
const DEFAULT_REPORT_DIR = '.sce/reports/problem-eval';
|
|
7
7
|
const STUDIO_STAGES = Object.freeze(['plan', 'generate', 'apply', 'verify', 'release']);
|
|
8
8
|
const DEBUG_EVIDENCE_TAGS = Object.freeze(['debug-evidence', 'diagnostic-evidence', 'debug-log']);
|
|
9
|
+
const ONTOLOGY_AXES = Object.freeze(['entity', 'relation', 'business_rule', 'decision_policy', 'execution_flow']);
|
|
9
10
|
|
|
10
11
|
const DEFAULT_PROBLEM_EVAL_POLICY = Object.freeze({
|
|
11
12
|
schema_version: '1.0',
|
|
@@ -32,7 +33,19 @@ const DEFAULT_PROBLEM_EVAL_POLICY = Object.freeze({
|
|
|
32
33
|
'compliance',
|
|
33
34
|
'data-loss'
|
|
34
35
|
],
|
|
35
|
-
recommendation_limit: 6
|
|
36
|
+
recommendation_limit: 6,
|
|
37
|
+
max_failed_rounds_before_debug: 2,
|
|
38
|
+
problem_contract_required_stages: [...STUDIO_STAGES],
|
|
39
|
+
problem_contract_block_stages: ['plan', 'apply', 'release'],
|
|
40
|
+
ontology_alignment_required_stages: [...STUDIO_STAGES],
|
|
41
|
+
ontology_alignment_block_stages: ['apply', 'release'],
|
|
42
|
+
ontology_required_axes: [...ONTOLOGY_AXES],
|
|
43
|
+
require_ontology_evidence_binding: true,
|
|
44
|
+
ontology_evidence_min_bindings: 1,
|
|
45
|
+
convergence_required_stages: ['verify', 'release'],
|
|
46
|
+
convergence_block_stages: ['release'],
|
|
47
|
+
release_block_on_high_alerts: true,
|
|
48
|
+
release_require_governance_report: false
|
|
36
49
|
});
|
|
37
50
|
|
|
38
51
|
function normalizeText(value) {
|
|
@@ -84,6 +97,36 @@ function normalizeArray(value = []) {
|
|
|
84
97
|
return value.map((item) => normalizeText(item)).filter(Boolean);
|
|
85
98
|
}
|
|
86
99
|
|
|
100
|
+
function normalizeTextList(value = [], limit = 20) {
|
|
101
|
+
if (!Array.isArray(value)) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
return value
|
|
105
|
+
.map((item) => {
|
|
106
|
+
if (typeof item === 'string') {
|
|
107
|
+
return normalizeText(item);
|
|
108
|
+
}
|
|
109
|
+
if (item && typeof item === 'object') {
|
|
110
|
+
return normalizeText(item.step || item.description || item.id || item.name || '');
|
|
111
|
+
}
|
|
112
|
+
return '';
|
|
113
|
+
})
|
|
114
|
+
.filter(Boolean)
|
|
115
|
+
.slice(0, limit);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function normalizeStageArray(value, fallback = []) {
|
|
119
|
+
const candidates = normalizeArray(value).map((item) => item.toLowerCase());
|
|
120
|
+
const filtered = candidates.filter((item, index) => STUDIO_STAGES.includes(item) && candidates.indexOf(item) === index);
|
|
121
|
+
return filtered.length > 0 ? filtered : [...fallback];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function normalizeOntologyAxisArray(value, fallback = []) {
|
|
125
|
+
const candidates = normalizeArray(value).map((item) => item.toLowerCase());
|
|
126
|
+
const filtered = candidates.filter((item, index) => ONTOLOGY_AXES.includes(item) && candidates.indexOf(item) === index);
|
|
127
|
+
return filtered.length > 0 ? filtered : [...fallback];
|
|
128
|
+
}
|
|
129
|
+
|
|
87
130
|
function normalizeIncidentState(value, fallback = 'open') {
|
|
88
131
|
const normalized = normalizeLowerText(value);
|
|
89
132
|
if (!normalized) {
|
|
@@ -133,12 +176,14 @@ function normalizePolicy(policy = {}, env = process.env) {
|
|
|
133
176
|
schema_version: normalizeText(policy.schema_version) || DEFAULT_PROBLEM_EVAL_POLICY.schema_version,
|
|
134
177
|
enabled,
|
|
135
178
|
mode: mode || DEFAULT_PROBLEM_EVAL_POLICY.mode,
|
|
136
|
-
enforce_on_stages:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
179
|
+
enforce_on_stages: normalizeStageArray(
|
|
180
|
+
policy.enforce_on_stages,
|
|
181
|
+
DEFAULT_PROBLEM_EVAL_POLICY.enforce_on_stages
|
|
182
|
+
),
|
|
183
|
+
block_on_stages: normalizeStageArray(
|
|
184
|
+
policy.block_on_stages,
|
|
185
|
+
DEFAULT_PROBLEM_EVAL_POLICY.block_on_stages
|
|
186
|
+
),
|
|
142
187
|
min_confidence_by_stage: {
|
|
143
188
|
plan: normalizeInteger(minByStage.plan, DEFAULT_PROBLEM_EVAL_POLICY.min_confidence_by_stage.plan, 0, 100),
|
|
144
189
|
generate: normalizeInteger(minByStage.generate, DEFAULT_PROBLEM_EVAL_POLICY.min_confidence_by_stage.generate, 0, 100),
|
|
@@ -158,6 +203,58 @@ function normalizePolicy(policy = {}, env = process.env) {
|
|
|
158
203
|
DEFAULT_PROBLEM_EVAL_POLICY.recommendation_limit,
|
|
159
204
|
1,
|
|
160
205
|
20
|
|
206
|
+
),
|
|
207
|
+
max_failed_rounds_before_debug: normalizeInteger(
|
|
208
|
+
policy.max_failed_rounds_before_debug,
|
|
209
|
+
DEFAULT_PROBLEM_EVAL_POLICY.max_failed_rounds_before_debug,
|
|
210
|
+
1,
|
|
211
|
+
10
|
|
212
|
+
),
|
|
213
|
+
problem_contract_required_stages: normalizeStageArray(
|
|
214
|
+
policy.problem_contract_required_stages,
|
|
215
|
+
DEFAULT_PROBLEM_EVAL_POLICY.problem_contract_required_stages
|
|
216
|
+
),
|
|
217
|
+
problem_contract_block_stages: normalizeStageArray(
|
|
218
|
+
policy.problem_contract_block_stages,
|
|
219
|
+
DEFAULT_PROBLEM_EVAL_POLICY.problem_contract_block_stages
|
|
220
|
+
),
|
|
221
|
+
ontology_alignment_required_stages: normalizeStageArray(
|
|
222
|
+
policy.ontology_alignment_required_stages,
|
|
223
|
+
DEFAULT_PROBLEM_EVAL_POLICY.ontology_alignment_required_stages
|
|
224
|
+
),
|
|
225
|
+
ontology_alignment_block_stages: normalizeStageArray(
|
|
226
|
+
policy.ontology_alignment_block_stages,
|
|
227
|
+
DEFAULT_PROBLEM_EVAL_POLICY.ontology_alignment_block_stages
|
|
228
|
+
),
|
|
229
|
+
ontology_required_axes: normalizeOntologyAxisArray(
|
|
230
|
+
policy.ontology_required_axes,
|
|
231
|
+
DEFAULT_PROBLEM_EVAL_POLICY.ontology_required_axes
|
|
232
|
+
),
|
|
233
|
+
require_ontology_evidence_binding: normalizeBoolean(
|
|
234
|
+
policy.require_ontology_evidence_binding,
|
|
235
|
+
DEFAULT_PROBLEM_EVAL_POLICY.require_ontology_evidence_binding
|
|
236
|
+
),
|
|
237
|
+
ontology_evidence_min_bindings: normalizeInteger(
|
|
238
|
+
policy.ontology_evidence_min_bindings,
|
|
239
|
+
DEFAULT_PROBLEM_EVAL_POLICY.ontology_evidence_min_bindings,
|
|
240
|
+
0,
|
|
241
|
+
20
|
|
242
|
+
),
|
|
243
|
+
convergence_required_stages: normalizeStageArray(
|
|
244
|
+
policy.convergence_required_stages,
|
|
245
|
+
DEFAULT_PROBLEM_EVAL_POLICY.convergence_required_stages
|
|
246
|
+
),
|
|
247
|
+
convergence_block_stages: normalizeStageArray(
|
|
248
|
+
policy.convergence_block_stages,
|
|
249
|
+
DEFAULT_PROBLEM_EVAL_POLICY.convergence_block_stages
|
|
250
|
+
),
|
|
251
|
+
release_block_on_high_alerts: normalizeBoolean(
|
|
252
|
+
policy.release_block_on_high_alerts,
|
|
253
|
+
DEFAULT_PROBLEM_EVAL_POLICY.release_block_on_high_alerts
|
|
254
|
+
),
|
|
255
|
+
release_require_governance_report: normalizeBoolean(
|
|
256
|
+
policy.release_require_governance_report,
|
|
257
|
+
DEFAULT_PROBLEM_EVAL_POLICY.release_require_governance_report
|
|
161
258
|
)
|
|
162
259
|
};
|
|
163
260
|
|
|
@@ -226,7 +323,8 @@ function scoreRisk(stage, text, policy, incidentSignals = {}, releaseChannel = '
|
|
|
226
323
|
score += Math.min(20, openIncidents * 3);
|
|
227
324
|
signals.push(`open-incidents:${openIncidents}`);
|
|
228
325
|
}
|
|
229
|
-
|
|
326
|
+
const debugRoundThreshold = Number(policy.max_failed_rounds_before_debug || 2) + 1;
|
|
327
|
+
if (maxAttempts >= debugRoundThreshold) {
|
|
230
328
|
score += 16;
|
|
231
329
|
signals.push(`repeat-attempts:${maxAttempts}`);
|
|
232
330
|
}
|
|
@@ -242,15 +340,262 @@ function scoreRisk(stage, text, policy, incidentSignals = {}, releaseChannel = '
|
|
|
242
340
|
return { score, level, signals };
|
|
243
341
|
}
|
|
244
342
|
|
|
343
|
+
function stageInPolicy(stage, list = []) {
|
|
344
|
+
return Array.isArray(list) && list.includes(stage);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function countOntologyEvidenceBindings(domainChain = {}, summary = {}) {
|
|
348
|
+
const summaryCount = Number(summary.evidence_binding_count || 0);
|
|
349
|
+
if (Number.isFinite(summaryCount) && summaryCount > 0) {
|
|
350
|
+
return summaryCount;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let total = 0;
|
|
354
|
+
const explicitBindings = Array.isArray(domainChain.evidence_bindings)
|
|
355
|
+
? domainChain.evidence_bindings.length
|
|
356
|
+
: 0;
|
|
357
|
+
total += explicitBindings;
|
|
358
|
+
|
|
359
|
+
const ontologyEvidence = domainChain.ontology_evidence && typeof domainChain.ontology_evidence === 'object'
|
|
360
|
+
? domainChain.ontology_evidence
|
|
361
|
+
: {};
|
|
362
|
+
for (const axis of ONTOLOGY_AXES) {
|
|
363
|
+
total += normalizeTextList(ontologyEvidence[axis], 50).length;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const hypotheses = Array.isArray(domainChain.hypotheses) ? domainChain.hypotheses : [];
|
|
367
|
+
for (const hypothesis of hypotheses.slice(0, 30)) {
|
|
368
|
+
total += normalizeTextList(hypothesis && hypothesis.evidence, 20).length;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return total;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function extractDomainChainSummary(domainChain = {}) {
|
|
375
|
+
const summary = domainChain.summary && typeof domainChain.summary === 'object'
|
|
376
|
+
? domainChain.summary
|
|
377
|
+
: {};
|
|
378
|
+
const payloadOntology = domainChain.ontology && typeof domainChain.ontology === 'object'
|
|
379
|
+
? domainChain.ontology
|
|
380
|
+
: {};
|
|
381
|
+
|
|
382
|
+
const fallbackCounts = {
|
|
383
|
+
entity: normalizeTextList(payloadOntology.entity, 50).length,
|
|
384
|
+
relation: normalizeTextList(payloadOntology.relation, 50).length,
|
|
385
|
+
business_rule: normalizeTextList(payloadOntology.business_rule, 50).length,
|
|
386
|
+
decision_policy: normalizeTextList(payloadOntology.decision_policy, 50).length,
|
|
387
|
+
execution_flow: normalizeTextList(payloadOntology.execution_flow, 50).length
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const summaryCounts = summary.ontology_counts && typeof summary.ontology_counts === 'object'
|
|
391
|
+
? summary.ontology_counts
|
|
392
|
+
: {};
|
|
393
|
+
const ontologyCounts = {
|
|
394
|
+
entity: Number(summaryCounts.entity || fallbackCounts.entity || 0),
|
|
395
|
+
relation: Number(summaryCounts.relation || fallbackCounts.relation || 0),
|
|
396
|
+
business_rule: Number(summaryCounts.business_rule || fallbackCounts.business_rule || 0),
|
|
397
|
+
decision_policy: Number(summaryCounts.decision_policy || fallbackCounts.decision_policy || 0),
|
|
398
|
+
execution_flow: Number(summaryCounts.execution_flow || fallbackCounts.execution_flow || 0)
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
ontology_counts: ontologyCounts,
|
|
403
|
+
decision_path_steps: Number(
|
|
404
|
+
summary.decision_path_steps
|
|
405
|
+
|| (Array.isArray(domainChain.decision_execution_path) ? domainChain.decision_execution_path.length : 0)
|
|
406
|
+
|| 0
|
|
407
|
+
),
|
|
408
|
+
verification_gates: Array.isArray(summary.verification_gates)
|
|
409
|
+
? summary.verification_gates
|
|
410
|
+
: (domainChain?.verification?.gates && Array.isArray(domainChain.verification.gates) ? domainChain.verification.gates : []),
|
|
411
|
+
hypothesis_count: Number(summary.hypothesis_count || (Array.isArray(domainChain.hypotheses) ? domainChain.hypotheses.length : 0) || 0),
|
|
412
|
+
risk_count: Number(summary.risk_count || (Array.isArray(domainChain.risks) ? domainChain.risks.length : 0) || 0),
|
|
413
|
+
evidence_binding_count: countOntologyEvidenceBindings(domainChain, summary)
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function deriveProblemContract(context = {}) {
|
|
418
|
+
const domainChain = context.domain_chain && typeof context.domain_chain === 'object'
|
|
419
|
+
? context.domain_chain
|
|
420
|
+
: {};
|
|
421
|
+
const chainContext = domainChain.context && typeof domainChain.context === 'object'
|
|
422
|
+
? domainChain.context
|
|
423
|
+
: {};
|
|
424
|
+
const contractRaw = context.problem_contract && typeof context.problem_contract === 'object'
|
|
425
|
+
? context.problem_contract
|
|
426
|
+
: {};
|
|
427
|
+
|
|
428
|
+
const issueStatement = normalizeText(
|
|
429
|
+
contractRaw.issue_statement
|
|
430
|
+
|| contractRaw.issue
|
|
431
|
+
|| contractRaw.problem_statement
|
|
432
|
+
|| chainContext?.problem?.statement
|
|
433
|
+
|| domainChain?.problem?.statement
|
|
434
|
+
|| context.goal
|
|
435
|
+
|| (context.scene_id ? `Stabilize scene ${normalizeText(context.scene_id)} execution.` : '')
|
|
436
|
+
);
|
|
437
|
+
const expectedOutcome = normalizeText(
|
|
438
|
+
contractRaw.expected_outcome
|
|
439
|
+
|| contractRaw.expected
|
|
440
|
+
|| contractRaw.success_criteria
|
|
441
|
+
|| chainContext?.verification?.plan
|
|
442
|
+
|| domainChain?.verification?.plan
|
|
443
|
+
|| (context.scene_id ? `Scene ${normalizeText(context.scene_id)} reaches deterministic verification gates.` : '')
|
|
444
|
+
);
|
|
445
|
+
const reproductionStepsRaw = normalizeTextList(
|
|
446
|
+
contractRaw.reproduction_steps
|
|
447
|
+
|| contractRaw.repro_steps
|
|
448
|
+
|| contractRaw.steps,
|
|
449
|
+
20
|
|
450
|
+
);
|
|
451
|
+
const reproductionSteps = reproductionStepsRaw.length > 0
|
|
452
|
+
? reproductionStepsRaw
|
|
453
|
+
: [
|
|
454
|
+
normalizeText(context.goal) || 'Reproduce the reported failure path in the target scene.',
|
|
455
|
+
'Capture execution trace and gate evidence for the failing path.'
|
|
456
|
+
].filter(Boolean);
|
|
457
|
+
const impactScope = normalizeText(
|
|
458
|
+
contractRaw.impact_scope
|
|
459
|
+
|| contractRaw.scope
|
|
460
|
+
|| chainContext?.problem?.scope
|
|
461
|
+
|| domainChain?.problem?.scope
|
|
462
|
+
|| context.scene_id
|
|
463
|
+
);
|
|
464
|
+
const forbiddenWorkaroundsRaw = normalizeTextList(
|
|
465
|
+
contractRaw.forbidden_workarounds
|
|
466
|
+
|| contractRaw.prohibited_workarounds
|
|
467
|
+
|| contractRaw.disallowed_workarounds,
|
|
468
|
+
20
|
|
469
|
+
);
|
|
470
|
+
const forbiddenWorkarounds = forbiddenWorkaroundsRaw.length > 0
|
|
471
|
+
? forbiddenWorkaroundsRaw
|
|
472
|
+
: [
|
|
473
|
+
'Do not bypass mandatory gates or tests.',
|
|
474
|
+
'Do not silence errors without root-cause remediation.'
|
|
475
|
+
];
|
|
476
|
+
return {
|
|
477
|
+
issue_statement: issueStatement,
|
|
478
|
+
expected_outcome: expectedOutcome,
|
|
479
|
+
reproduction_steps: reproductionSteps,
|
|
480
|
+
impact_scope: impactScope,
|
|
481
|
+
forbidden_workarounds: forbiddenWorkarounds
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function evaluateProblemContract(context = {}) {
|
|
486
|
+
const contract = deriveProblemContract(context);
|
|
487
|
+
const checks = {
|
|
488
|
+
issue_statement: normalizeText(contract.issue_statement).length > 0,
|
|
489
|
+
expected_outcome: normalizeText(contract.expected_outcome).length > 0,
|
|
490
|
+
reproduction_steps: Array.isArray(contract.reproduction_steps) && contract.reproduction_steps.length > 0,
|
|
491
|
+
impact_scope: normalizeText(contract.impact_scope).length > 0,
|
|
492
|
+
forbidden_workarounds: Array.isArray(contract.forbidden_workarounds) && contract.forbidden_workarounds.length > 0
|
|
493
|
+
};
|
|
494
|
+
const total = Object.keys(checks).length;
|
|
495
|
+
const covered = Object.values(checks).filter(Boolean).length;
|
|
496
|
+
return {
|
|
497
|
+
contract,
|
|
498
|
+
checks,
|
|
499
|
+
total,
|
|
500
|
+
covered,
|
|
501
|
+
missing: Object.keys(checks).filter((key) => !checks[key]),
|
|
502
|
+
score: Math.round((covered / total) * 100),
|
|
503
|
+
passed: covered === total
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function evaluateOntologyAlignment(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLICY) {
|
|
508
|
+
const domainChain = context.domain_chain && typeof context.domain_chain === 'object'
|
|
509
|
+
? context.domain_chain
|
|
510
|
+
: {};
|
|
511
|
+
const summary = extractDomainChainSummary(domainChain);
|
|
512
|
+
const requiredAxes = Array.isArray(policy.ontology_required_axes) && policy.ontology_required_axes.length > 0
|
|
513
|
+
? policy.ontology_required_axes
|
|
514
|
+
: [...ONTOLOGY_AXES];
|
|
515
|
+
const missingAxes = requiredAxes.filter((axis) => Number(summary?.ontology_counts?.[axis] || 0) <= 0);
|
|
516
|
+
const evidenceBindingCount = Number(summary.evidence_binding_count || 0);
|
|
517
|
+
const minBindings = Number(policy.ontology_evidence_min_bindings || 0);
|
|
518
|
+
const hasDomainMaterial = domainChain.resolved === true
|
|
519
|
+
|| ONTOLOGY_AXES.some((axis) => Number(summary?.ontology_counts?.[axis] || 0) > 0)
|
|
520
|
+
|| normalizeText(context.spec_id).length > 0;
|
|
521
|
+
if (!hasDomainMaterial) {
|
|
522
|
+
return {
|
|
523
|
+
required_axes: requiredAxes,
|
|
524
|
+
missing_axes: [],
|
|
525
|
+
ontology_counts: summary.ontology_counts,
|
|
526
|
+
evidence_binding_count: evidenceBindingCount,
|
|
527
|
+
required_evidence_bindings: minBindings,
|
|
528
|
+
evidence_satisfied: true,
|
|
529
|
+
score: 100,
|
|
530
|
+
passed: true,
|
|
531
|
+
skipped: true
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const evidenceSatisfied = policy.require_ontology_evidence_binding !== true
|
|
535
|
+
? true
|
|
536
|
+
: evidenceBindingCount >= minBindings;
|
|
537
|
+
|
|
538
|
+
let score = 0;
|
|
539
|
+
if (requiredAxes.length > 0) {
|
|
540
|
+
score += Math.round(((requiredAxes.length - missingAxes.length) / requiredAxes.length) * 80);
|
|
541
|
+
}
|
|
542
|
+
if (evidenceSatisfied) {
|
|
543
|
+
score += 20;
|
|
544
|
+
}
|
|
545
|
+
score = Math.max(0, Math.min(100, score));
|
|
546
|
+
|
|
547
|
+
return {
|
|
548
|
+
required_axes: requiredAxes,
|
|
549
|
+
missing_axes: missingAxes,
|
|
550
|
+
ontology_counts: summary.ontology_counts,
|
|
551
|
+
evidence_binding_count: evidenceBindingCount,
|
|
552
|
+
required_evidence_bindings: minBindings,
|
|
553
|
+
evidence_satisfied: evidenceSatisfied,
|
|
554
|
+
score,
|
|
555
|
+
passed: missingAxes.length === 0 && evidenceSatisfied
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function evaluateConvergence(context = {}, stage = '', policy = DEFAULT_PROBLEM_EVAL_POLICY) {
|
|
560
|
+
const readiness = context.stage_readiness && typeof context.stage_readiness === 'object'
|
|
561
|
+
? context.stage_readiness
|
|
562
|
+
: {};
|
|
563
|
+
const checks = {
|
|
564
|
+
prerequisites_ready: readiness.prerequisites_ready === true
|
|
565
|
+
};
|
|
566
|
+
if (stage === 'release') {
|
|
567
|
+
checks.verify_report_ready = readiness.verify_report_ready === true;
|
|
568
|
+
checks.verify_stage_passed = readiness.verify_stage_passed !== false;
|
|
569
|
+
checks.regression_passed = readiness.regression_passed !== false;
|
|
570
|
+
const highAlertCount = Number(readiness.high_alert_count || 0);
|
|
571
|
+
checks.high_alerts_clear = policy.release_block_on_high_alerts === true
|
|
572
|
+
? highAlertCount <= 0
|
|
573
|
+
: true;
|
|
574
|
+
if (policy.release_require_governance_report === true) {
|
|
575
|
+
checks.governance_report_ready = readiness.governance_report_ready === true;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const total = Object.keys(checks).length;
|
|
580
|
+
const covered = Object.values(checks).filter(Boolean).length;
|
|
581
|
+
const missing = Object.keys(checks).filter((key) => !checks[key]);
|
|
582
|
+
const score = total > 0 ? Math.round((covered / total) * 100) : 100;
|
|
583
|
+
|
|
584
|
+
return {
|
|
585
|
+
checks,
|
|
586
|
+
missing,
|
|
587
|
+
score,
|
|
588
|
+
passed: missing.length === 0
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
245
592
|
function scoreEvidence(context = {}, incidentSignals = {}) {
|
|
246
593
|
const signals = [];
|
|
247
594
|
let score = 0;
|
|
248
595
|
const domainChain = context.domain_chain && typeof context.domain_chain === 'object'
|
|
249
596
|
? context.domain_chain
|
|
250
597
|
: {};
|
|
251
|
-
const summary = domainChain
|
|
252
|
-
? domainChain.summary
|
|
253
|
-
: {};
|
|
598
|
+
const summary = extractDomainChainSummary(domainChain);
|
|
254
599
|
|
|
255
600
|
if (domainChain.resolved === true) {
|
|
256
601
|
score += 20;
|
|
@@ -293,6 +638,11 @@ function scoreEvidence(context = {}, incidentSignals = {}) {
|
|
|
293
638
|
score += 6;
|
|
294
639
|
signals.push('required-gates-available');
|
|
295
640
|
}
|
|
641
|
+
const evidenceBindingCount = Number(summary.evidence_binding_count || 0);
|
|
642
|
+
if (evidenceBindingCount > 0) {
|
|
643
|
+
score += Math.min(10, evidenceBindingCount);
|
|
644
|
+
signals.push(`ontology-evidence-bindings:${evidenceBindingCount}`);
|
|
645
|
+
}
|
|
296
646
|
|
|
297
647
|
score = Math.max(0, Math.min(100, Math.round(score)));
|
|
298
648
|
return { score, signals };
|
|
@@ -347,7 +697,8 @@ function scoreReadiness(context = {}) {
|
|
|
347
697
|
function deriveStrategy(stage, risk, evidence, confidence, incidentSignals = {}, policy = DEFAULT_PROBLEM_EVAL_POLICY) {
|
|
348
698
|
const reasons = [];
|
|
349
699
|
let strategy = 'direct-execution';
|
|
350
|
-
|
|
700
|
+
const debugAttemptThreshold = Number(policy.max_failed_rounds_before_debug || 2) + 1;
|
|
701
|
+
if (Number(incidentSignals.max_attempt_count || 0) >= debugAttemptThreshold
|
|
351
702
|
&& policy.high_risk_requires_debug_evidence
|
|
352
703
|
&& incidentSignals.has_debug_evidence !== true) {
|
|
353
704
|
strategy = 'debug-first';
|
|
@@ -393,8 +744,16 @@ function evaluateProblemContext(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLI
|
|
|
393
744
|
const risk = scoreRisk(stage, textForRisk, policy, incidentSignals, context.release_channel);
|
|
394
745
|
const evidence = scoreEvidence(context, incidentSignals);
|
|
395
746
|
const readiness = scoreReadiness(context);
|
|
747
|
+
const problemContract = evaluateProblemContract(context);
|
|
748
|
+
const ontologyAlignment = evaluateOntologyAlignment(context, policy);
|
|
749
|
+
const convergence = evaluateConvergence(context, stage, policy);
|
|
396
750
|
const confidenceScore = Math.max(0, Math.min(100, Math.round(
|
|
397
|
-
evidence.score * 0.
|
|
751
|
+
evidence.score * 0.32
|
|
752
|
+
+ readiness.score * 0.24
|
|
753
|
+
+ (100 - risk.score) * 0.14
|
|
754
|
+
+ problemContract.score * 0.15
|
|
755
|
+
+ ontologyAlignment.score * 0.10
|
|
756
|
+
+ convergence.score * 0.05
|
|
398
757
|
)));
|
|
399
758
|
|
|
400
759
|
const minConfidence = Number(policy?.min_confidence_by_stage?.[stage] || 0);
|
|
@@ -413,9 +772,10 @@ function evaluateProblemContext(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLI
|
|
|
413
772
|
}
|
|
414
773
|
}
|
|
415
774
|
|
|
775
|
+
const debugAttemptThreshold = Number(policy.max_failed_rounds_before_debug || 2) + 1;
|
|
416
776
|
if (policy.high_risk_requires_debug_evidence
|
|
417
777
|
&& risk.level === 'high'
|
|
418
|
-
&& Number(incidentSignals.max_attempt_count || 0) >=
|
|
778
|
+
&& Number(incidentSignals.max_attempt_count || 0) >= debugAttemptThreshold
|
|
419
779
|
&& incidentSignals.has_debug_evidence !== true) {
|
|
420
780
|
warnings.push('high risk with repeated failed attempts and no debug evidence');
|
|
421
781
|
if (blockStage) {
|
|
@@ -430,6 +790,47 @@ function evaluateProblemContext(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLI
|
|
|
430
790
|
}
|
|
431
791
|
}
|
|
432
792
|
|
|
793
|
+
const problemContractRequired = stageInPolicy(stage, policy.problem_contract_required_stages);
|
|
794
|
+
const problemContractBlockedStage = stageInPolicy(stage, policy.problem_contract_block_stages);
|
|
795
|
+
if (problemContractRequired && !problemContract.passed) {
|
|
796
|
+
warnings.push(`problem contract incomplete: ${problemContract.missing.join(', ')}`);
|
|
797
|
+
if (problemContractBlockedStage) {
|
|
798
|
+
blockers.push(`problem-contract-incomplete:${problemContract.missing.join('|')}`);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const ontologyRequired = stageInPolicy(stage, policy.ontology_alignment_required_stages);
|
|
803
|
+
const ontologyBlockedStage = stageInPolicy(stage, policy.ontology_alignment_block_stages);
|
|
804
|
+
if (ontologyRequired && !ontologyAlignment.passed) {
|
|
805
|
+
if (ontologyAlignment.missing_axes.length > 0) {
|
|
806
|
+
warnings.push(`ontology alignment missing axes: ${ontologyAlignment.missing_axes.join(', ')}`);
|
|
807
|
+
}
|
|
808
|
+
if (!ontologyAlignment.evidence_satisfied) {
|
|
809
|
+
warnings.push(
|
|
810
|
+
`ontology evidence binding below threshold: ${ontologyAlignment.evidence_binding_count}<${ontologyAlignment.required_evidence_bindings}`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
if (ontologyBlockedStage) {
|
|
814
|
+
if (ontologyAlignment.missing_axes.length > 0) {
|
|
815
|
+
blockers.push(`ontology-alignment-missing:${ontologyAlignment.missing_axes.join('|')}`);
|
|
816
|
+
}
|
|
817
|
+
if (!ontologyAlignment.evidence_satisfied) {
|
|
818
|
+
blockers.push(
|
|
819
|
+
`ontology-evidence-binding-low:${ontologyAlignment.evidence_binding_count}<${ontologyAlignment.required_evidence_bindings}`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const convergenceRequired = stageInPolicy(stage, policy.convergence_required_stages);
|
|
826
|
+
const convergenceBlockedStage = stageInPolicy(stage, policy.convergence_block_stages);
|
|
827
|
+
if (convergenceRequired && !convergence.passed) {
|
|
828
|
+
warnings.push(`convergence checks pending: ${convergence.missing.join(', ')}`);
|
|
829
|
+
if (convergenceBlockedStage) {
|
|
830
|
+
blockers.push(`convergence-gate-missing:${convergence.missing.join('|')}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
433
834
|
const recommendations = [];
|
|
434
835
|
if (strategy.strategy === 'debug-first') {
|
|
435
836
|
recommendations.push('Capture debug trace/log evidence before the next patch attempt.');
|
|
@@ -444,12 +845,22 @@ function evaluateProblemContext(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLI
|
|
|
444
845
|
if (Number(incidentSignals.open_incident_count || 0) > 0) {
|
|
445
846
|
recommendations.push('Review staging incident attempts to avoid repeating failed actions.');
|
|
446
847
|
}
|
|
848
|
+
if (!problemContract.passed) {
|
|
849
|
+
recommendations.push('Complete the problem contract: issue, expected outcome, reproduction steps, impact scope, and forbidden workarounds.');
|
|
850
|
+
}
|
|
851
|
+
if (!ontologyAlignment.passed) {
|
|
852
|
+
recommendations.push('Fill missing ontology axes and bind evidence references before further remediation.');
|
|
853
|
+
}
|
|
854
|
+
if (!convergence.passed) {
|
|
855
|
+
recommendations.push('Close convergence checks (verify pass, regression pass, high-alert clear) before release.');
|
|
856
|
+
}
|
|
447
857
|
if (recommendations.length === 0) {
|
|
448
858
|
recommendations.push('Proceed with direct execution and keep gate verification enabled.');
|
|
449
859
|
}
|
|
450
860
|
|
|
451
861
|
const cappedRecommendations = recommendations.slice(0, policy.recommendation_limit || 6);
|
|
452
|
-
const
|
|
862
|
+
const hardBlockStage = blockStage || problemContractBlockedStage || ontologyBlockedStage || convergenceBlockedStage;
|
|
863
|
+
const blocked = enforced && hardBlockStage && !advisoryMode && blockers.length > 0;
|
|
453
864
|
|
|
454
865
|
return {
|
|
455
866
|
mode: 'problem-eval',
|
|
@@ -464,13 +875,17 @@ function evaluateProblemContext(context = {}, policy = DEFAULT_PROBLEM_EVAL_POLI
|
|
|
464
875
|
mode: policy.mode,
|
|
465
876
|
enforced,
|
|
466
877
|
block_stage: blockStage,
|
|
878
|
+
hard_block_stage: hardBlockStage,
|
|
467
879
|
min_confidence: minConfidence
|
|
468
880
|
},
|
|
469
881
|
dimensions: {
|
|
470
882
|
risk,
|
|
471
883
|
evidence,
|
|
472
884
|
readiness,
|
|
473
|
-
strategy
|
|
885
|
+
strategy,
|
|
886
|
+
problem_contract: problemContract,
|
|
887
|
+
ontology_alignment: ontologyAlignment,
|
|
888
|
+
convergence
|
|
474
889
|
},
|
|
475
890
|
incident_signals: {
|
|
476
891
|
...incidentSignals
|
|
@@ -4,6 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const DOMAIN_MAP_RELATIVE_PATH = path.join('custom', 'problem-domain-map.md');
|
|
5
5
|
const SCENE_SPEC_RELATIVE_PATH = path.join('custom', 'scene-spec.md');
|
|
6
6
|
const DOMAIN_CHAIN_RELATIVE_PATH = path.join('custom', 'problem-domain-chain.json');
|
|
7
|
+
const PROBLEM_CONTRACT_RELATIVE_PATH = path.join('custom', 'problem-contract.json');
|
|
7
8
|
const DOMAIN_CHAIN_API_VERSION = 'sce.problem-domain-chain/v0.1';
|
|
8
9
|
const DOMAIN_RESEARCH_DIMENSIONS = Object.freeze([
|
|
9
10
|
'scene_boundary',
|
|
@@ -30,7 +31,30 @@ function resolveSpecPaths(projectPath, specId) {
|
|
|
30
31
|
specPath,
|
|
31
32
|
domainMapPath: path.join(specPath, DOMAIN_MAP_RELATIVE_PATH),
|
|
32
33
|
sceneSpecPath: path.join(specPath, SCENE_SPEC_RELATIVE_PATH),
|
|
33
|
-
domainChainPath: path.join(specPath, DOMAIN_CHAIN_RELATIVE_PATH)
|
|
34
|
+
domainChainPath: path.join(specPath, DOMAIN_CHAIN_RELATIVE_PATH),
|
|
35
|
+
problemContractPath: path.join(specPath, PROBLEM_CONTRACT_RELATIVE_PATH)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildProblemContract(specId, options = {}) {
|
|
40
|
+
const sceneId = normalizeText(options.sceneId) || `scene.${specId.replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase()}`;
|
|
41
|
+
const problemStatement = normalizeText(options.problemStatement) || 'TBD: describe the primary business problem';
|
|
42
|
+
const verificationPlan = normalizeText(options.verificationPlan) || 'TBD: define validation and rollback criteria';
|
|
43
|
+
return {
|
|
44
|
+
schema_version: '1.0',
|
|
45
|
+
spec_id: specId,
|
|
46
|
+
scene_id: sceneId,
|
|
47
|
+
issue_statement: problemStatement,
|
|
48
|
+
expected_outcome: verificationPlan,
|
|
49
|
+
reproduction_steps: [
|
|
50
|
+
'Reproduce the issue along the failing scene path.',
|
|
51
|
+
'Capture gate/test/runtime evidence for failed behavior.'
|
|
52
|
+
],
|
|
53
|
+
impact_scope: `scene=${sceneId}`,
|
|
54
|
+
forbidden_workarounds: [
|
|
55
|
+
'Do not bypass mandatory gates or tests.',
|
|
56
|
+
'Do not silence runtime errors without root-cause remediation.'
|
|
57
|
+
]
|
|
34
58
|
};
|
|
35
59
|
}
|
|
36
60
|
|
|
@@ -274,6 +298,14 @@ function buildProblemDomainChain(specId, options = {}) {
|
|
|
274
298
|
'tests',
|
|
275
299
|
'release preflight'
|
|
276
300
|
]
|
|
301
|
+
},
|
|
302
|
+
problem_contract: buildProblemContract(specId, options),
|
|
303
|
+
ontology_evidence: {
|
|
304
|
+
entity: ['Entity mapping evidence: model/schema reference'],
|
|
305
|
+
relation: ['Relation mapping evidence: join/foreign-key or service linkage'],
|
|
306
|
+
business_rule: ['Rule evidence: validation/policy check reference'],
|
|
307
|
+
decision_policy: ['Decision evidence: branch condition and policy source'],
|
|
308
|
+
execution_flow: ['Execution evidence: service/screen/runtime trace path']
|
|
277
309
|
}
|
|
278
310
|
};
|
|
279
311
|
}
|
|
@@ -479,11 +511,13 @@ async function ensureSpecDomainArtifacts(projectPath, specId, options = {}) {
|
|
|
479
511
|
const domainMapContent = buildProblemDomainMindMap(specId, options);
|
|
480
512
|
const sceneSpecContent = buildSceneSpec(specId, options);
|
|
481
513
|
const domainChainPayload = buildProblemDomainChain(specId, options);
|
|
514
|
+
const problemContractPayload = buildProblemContract(specId, options);
|
|
482
515
|
|
|
483
516
|
const created = {
|
|
484
517
|
domain_map: false,
|
|
485
518
|
scene_spec: false,
|
|
486
|
-
domain_chain: false
|
|
519
|
+
domain_chain: false,
|
|
520
|
+
problem_contract: false
|
|
487
521
|
};
|
|
488
522
|
|
|
489
523
|
if (!dryRun) {
|
|
@@ -506,23 +540,32 @@ async function ensureSpecDomainArtifacts(projectPath, specId, options = {}) {
|
|
|
506
540
|
await fileSystem.writeJson(paths.domainChainPath, domainChainPayload, { spaces: 2 });
|
|
507
541
|
created.domain_chain = true;
|
|
508
542
|
}
|
|
543
|
+
|
|
544
|
+
const hasProblemContract = await fileSystem.pathExists(paths.problemContractPath);
|
|
545
|
+
if (force || !hasProblemContract) {
|
|
546
|
+
await fileSystem.writeJson(paths.problemContractPath, problemContractPayload, { spaces: 2 });
|
|
547
|
+
created.problem_contract = true;
|
|
548
|
+
}
|
|
509
549
|
} else {
|
|
510
550
|
created.domain_map = true;
|
|
511
551
|
created.scene_spec = true;
|
|
512
552
|
created.domain_chain = true;
|
|
553
|
+
created.problem_contract = true;
|
|
513
554
|
}
|
|
514
555
|
|
|
515
556
|
return {
|
|
516
557
|
paths: {
|
|
517
558
|
domain_map: paths.domainMapPath,
|
|
518
559
|
scene_spec: paths.sceneSpecPath,
|
|
519
|
-
domain_chain: paths.domainChainPath
|
|
560
|
+
domain_chain: paths.domainChainPath,
|
|
561
|
+
problem_contract: paths.problemContractPath
|
|
520
562
|
},
|
|
521
563
|
created,
|
|
522
564
|
preview: {
|
|
523
565
|
domain_map: domainMapContent,
|
|
524
566
|
scene_spec: sceneSpecContent,
|
|
525
|
-
domain_chain: domainChainPayload
|
|
567
|
+
domain_chain: domainChainPayload,
|
|
568
|
+
problem_contract: problemContractPayload
|
|
526
569
|
}
|
|
527
570
|
};
|
|
528
571
|
}
|
|
@@ -644,11 +687,13 @@ module.exports = {
|
|
|
644
687
|
DOMAIN_MAP_RELATIVE_PATH,
|
|
645
688
|
SCENE_SPEC_RELATIVE_PATH,
|
|
646
689
|
DOMAIN_CHAIN_RELATIVE_PATH,
|
|
690
|
+
PROBLEM_CONTRACT_RELATIVE_PATH,
|
|
647
691
|
DOMAIN_CHAIN_API_VERSION,
|
|
648
692
|
DOMAIN_RESEARCH_DIMENSIONS,
|
|
649
693
|
buildProblemDomainMindMap,
|
|
650
694
|
buildSceneSpec,
|
|
651
695
|
buildProblemDomainChain,
|
|
696
|
+
buildProblemContract,
|
|
652
697
|
ensureSpecDomainArtifacts,
|
|
653
698
|
validateSpecDomainArtifacts,
|
|
654
699
|
analyzeSpecDomainCoverage
|