scene-capability-engine 3.3.26 → 3.4.6
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 +82 -0
- package/README.md +100 -711
- package/README.zh.md +103 -577
- package/bin/scene-capability-engine.js +103 -0
- package/docs/README.md +47 -249
- package/docs/command-reference.md +84 -9
- package/docs/images/wechat-qr.png +0 -0
- package/docs/spec-workflow.md +35 -4
- package/docs/zh/README.md +44 -331
- package/lib/adoption/adoption-strategy.js +5 -0
- package/lib/adoption/detection-engine.js +5 -0
- package/lib/adoption/file-classifier.js +6 -1
- package/lib/adoption/smart-orchestrator.js +5 -0
- package/lib/commands/adopt.js +32 -0
- package/lib/commands/errorbook.js +551 -4
- package/lib/commands/spec-domain.js +78 -2
- package/lib/commands/studio.js +550 -9
- package/lib/commands/upgrade.js +16 -0
- package/lib/problem/problem-evaluator.js +1035 -0
- package/lib/spec/domain-modeling.js +266 -5
- package/lib/workspace/takeover-baseline.js +514 -0
- package/package.json +1 -1
- package/template/.sce/config/problem-closure-policy.json +18 -0
- package/template/.sce/config/problem-eval-policy.json +78 -0
- package/template/.sce/config/session-governance.json +8 -0
- package/template/.sce/config/spec-domain-policy.json +14 -0
- package/template/.sce/config/takeover-baseline.json +33 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +4 -2
package/lib/commands/studio.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
} = require('../spec/domain-modeling');
|
|
11
11
|
const { findRelatedSpecs } = require('../spec/related-specs');
|
|
12
12
|
const { captureTimelineCheckpoint } = require('../runtime/project-timeline');
|
|
13
|
+
const { runProblemEvaluation } = require('../problem/problem-evaluator');
|
|
13
14
|
|
|
14
15
|
const STUDIO_JOB_API_VERSION = 'sce.studio.job/v0.1';
|
|
15
16
|
const STAGE_ORDER = ['plan', 'generate', 'apply', 'verify', 'release'];
|
|
@@ -18,6 +19,8 @@ const STUDIO_EVENT_API_VERSION = 'sce.studio.event/v0.1';
|
|
|
18
19
|
const VERIFY_PROFILES = new Set(['fast', 'standard', 'strict']);
|
|
19
20
|
const RELEASE_PROFILES = new Set(['standard', 'strict']);
|
|
20
21
|
const STUDIO_REPORTS_DIR = '.sce/reports/studio';
|
|
22
|
+
const DEFAULT_INTERACTIVE_GOVERNANCE_REPORT = '.sce/reports/interactive-governance-report.json';
|
|
23
|
+
const DEFAULT_PROBLEM_CONTRACT_RELATIVE_PATH = path.join('custom', 'problem-contract.json');
|
|
21
24
|
const MAX_OUTPUT_PREVIEW_LENGTH = 2000;
|
|
22
25
|
const DEFAULT_STUDIO_SECURITY_POLICY = Object.freeze({
|
|
23
26
|
enabled: false,
|
|
@@ -367,6 +370,7 @@ async function buildVerifyGateSteps(options = {}, dependencies = {}) {
|
|
|
367
370
|
const projectPath = dependencies.projectPath || process.cwd();
|
|
368
371
|
const fileSystem = dependencies.fileSystem || fs;
|
|
369
372
|
const profile = normalizeString(options.profile) || 'standard';
|
|
373
|
+
const specId = normalizeString(options.specId || dependencies.specId);
|
|
370
374
|
|
|
371
375
|
if (!VERIFY_PROFILES.has(profile)) {
|
|
372
376
|
throw new Error(`Invalid verify profile "${profile}". Expected one of: ${Array.from(VERIFY_PROFILES).join(', ')}`);
|
|
@@ -402,6 +406,21 @@ async function buildVerifyGateSteps(options = {}, dependencies = {}) {
|
|
|
402
406
|
}
|
|
403
407
|
|
|
404
408
|
if (profile === 'standard' || profile === 'strict') {
|
|
409
|
+
const problemClosureGateScript = path.join(projectPath, 'scripts', 'problem-closure-gate.js');
|
|
410
|
+
const hasProblemClosureGateScript = await fileSystem.pathExists(problemClosureGateScript);
|
|
411
|
+
const canRunProblemClosureGate = hasProblemClosureGateScript && Boolean(specId);
|
|
412
|
+
steps.push({
|
|
413
|
+
id: 'problem-closure-gate',
|
|
414
|
+
name: 'problem closure gate (verify)',
|
|
415
|
+
command: 'node',
|
|
416
|
+
args: ['scripts/problem-closure-gate.js', '--stage', 'verify', '--spec', specId, '--fail-on-block', '--json'],
|
|
417
|
+
required: Boolean(specId),
|
|
418
|
+
enabled: canRunProblemClosureGate,
|
|
419
|
+
skip_reason: canRunProblemClosureGate
|
|
420
|
+
? ''
|
|
421
|
+
: (specId ? 'scripts/problem-closure-gate.js not found' : 'spec id unavailable for problem-closure gate')
|
|
422
|
+
});
|
|
423
|
+
|
|
405
424
|
const governanceScript = path.join(projectPath, 'scripts', 'interactive-governance-report.js');
|
|
406
425
|
const hasGovernanceScript = await fileSystem.pathExists(governanceScript);
|
|
407
426
|
steps.push({
|
|
@@ -434,11 +453,32 @@ async function buildReleaseGateSteps(options = {}, dependencies = {}) {
|
|
|
434
453
|
const projectPath = dependencies.projectPath || process.cwd();
|
|
435
454
|
const fileSystem = dependencies.fileSystem || fs;
|
|
436
455
|
const profile = normalizeString(options.profile) || 'standard';
|
|
456
|
+
const specId = normalizeString(options.specId || dependencies.specId);
|
|
457
|
+
const verifyReportPath = normalizeString(options.verifyReportPath || dependencies.verifyReportPath);
|
|
437
458
|
if (!RELEASE_PROFILES.has(profile)) {
|
|
438
459
|
throw new Error(`Invalid release profile "${profile}". Expected one of: ${Array.from(RELEASE_PROFILES).join(', ')}`);
|
|
439
460
|
}
|
|
440
461
|
|
|
441
462
|
const steps = [];
|
|
463
|
+
const problemClosureGateScript = path.join(projectPath, 'scripts', 'problem-closure-gate.js');
|
|
464
|
+
const hasProblemClosureGateScript = await fileSystem.pathExists(problemClosureGateScript);
|
|
465
|
+
const canRunProblemClosureGate = hasProblemClosureGateScript && Boolean(specId);
|
|
466
|
+
const problemClosureArgs = ['scripts/problem-closure-gate.js', '--stage', 'release', '--spec', specId, '--fail-on-block', '--json'];
|
|
467
|
+
if (verifyReportPath) {
|
|
468
|
+
problemClosureArgs.push('--verify-report', verifyReportPath);
|
|
469
|
+
}
|
|
470
|
+
steps.push({
|
|
471
|
+
id: 'problem-closure-gate',
|
|
472
|
+
name: 'problem closure gate (release)',
|
|
473
|
+
command: 'node',
|
|
474
|
+
args: problemClosureArgs,
|
|
475
|
+
required: Boolean(specId),
|
|
476
|
+
enabled: canRunProblemClosureGate,
|
|
477
|
+
skip_reason: canRunProblemClosureGate
|
|
478
|
+
? ''
|
|
479
|
+
: (specId ? 'scripts/problem-closure-gate.js not found' : 'spec id unavailable for problem-closure gate')
|
|
480
|
+
});
|
|
481
|
+
|
|
442
482
|
steps.push({
|
|
443
483
|
id: 'npm-pack-dry-run',
|
|
444
484
|
name: 'npm pack --dry-run',
|
|
@@ -709,6 +749,77 @@ async function readSpecDomainChain(projectPath, specId, fileSystem = fs) {
|
|
|
709
749
|
}
|
|
710
750
|
}
|
|
711
751
|
|
|
752
|
+
async function readSpecProblemContract(projectPath, specId, fileSystem = fs) {
|
|
753
|
+
const specRoot = path.join(projectPath, '.sce', 'specs', specId);
|
|
754
|
+
const contractPath = path.join(specRoot, DEFAULT_PROBLEM_CONTRACT_RELATIVE_PATH);
|
|
755
|
+
if (!await fileSystem.pathExists(contractPath)) {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
try {
|
|
759
|
+
const payload = await fileSystem.readJson(contractPath);
|
|
760
|
+
const stat = await fileSystem.stat(contractPath);
|
|
761
|
+
return {
|
|
762
|
+
spec_id: specId,
|
|
763
|
+
contract_path: toRelativePosix(projectPath, contractPath),
|
|
764
|
+
payload,
|
|
765
|
+
updated_at: stat && stat.mtime ? stat.mtime.toISOString() : null,
|
|
766
|
+
mtime_ms: Number(stat && stat.mtimeMs) || 0
|
|
767
|
+
};
|
|
768
|
+
} catch (_error) {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
async function readGovernanceSignals(projectPath, fileSystem = fs) {
|
|
774
|
+
const reportPath = path.join(projectPath, DEFAULT_INTERACTIVE_GOVERNANCE_REPORT);
|
|
775
|
+
if (!await fileSystem.pathExists(reportPath)) {
|
|
776
|
+
return {
|
|
777
|
+
available: false,
|
|
778
|
+
report_path: null,
|
|
779
|
+
high_breach_count: 0,
|
|
780
|
+
medium_breach_count: 0
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
const payload = await fileSystem.readJson(reportPath).catch(() => null);
|
|
784
|
+
const summary = extractGovernanceBreachSignals(payload || {});
|
|
785
|
+
return {
|
|
786
|
+
...summary,
|
|
787
|
+
report_path: toRelativePosix(projectPath, reportPath)
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
async function readVerifyReportSignals(projectPath, verifyReportPath = '', fileSystem = fs) {
|
|
792
|
+
const normalized = normalizeString(verifyReportPath);
|
|
793
|
+
if (!normalized) {
|
|
794
|
+
return {
|
|
795
|
+
available: false,
|
|
796
|
+
report_path: null,
|
|
797
|
+
passed: false,
|
|
798
|
+
failed_step_count: 0
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
const absolutePath = path.isAbsolute(normalized)
|
|
802
|
+
? normalized
|
|
803
|
+
: path.join(projectPath, normalized);
|
|
804
|
+
if (!await fileSystem.pathExists(absolutePath)) {
|
|
805
|
+
return {
|
|
806
|
+
available: false,
|
|
807
|
+
report_path: normalized,
|
|
808
|
+
passed: false,
|
|
809
|
+
failed_step_count: 0
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
const payload = await fileSystem.readJson(absolutePath).catch(() => null);
|
|
813
|
+
const steps = Array.isArray(payload && payload.steps) ? payload.steps : [];
|
|
814
|
+
const failedStepCount = steps.filter((step) => normalizeString(step && step.status) === 'failed').length;
|
|
815
|
+
return {
|
|
816
|
+
available: true,
|
|
817
|
+
report_path: toRelativePosix(projectPath, absolutePath),
|
|
818
|
+
passed: payload && payload.passed === true && failedStepCount === 0,
|
|
819
|
+
failed_step_count: failedStepCount
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
|
|
712
823
|
function normalizeChainList(value, limit = 5) {
|
|
713
824
|
if (!Array.isArray(value)) {
|
|
714
825
|
return [];
|
|
@@ -724,13 +835,97 @@ function normalizeChainList(value, limit = 5) {
|
|
|
724
835
|
});
|
|
725
836
|
}
|
|
726
837
|
|
|
838
|
+
function normalizeProblemContract(contract = {}, context = {}) {
|
|
839
|
+
const source = contract && typeof contract === 'object' ? contract : {};
|
|
840
|
+
const issueStatement = normalizeString(
|
|
841
|
+
source.issue_statement
|
|
842
|
+
|| source.issue
|
|
843
|
+
|| source.problem_statement
|
|
844
|
+
|| context.problem_statement
|
|
845
|
+
|| context.goal
|
|
846
|
+
);
|
|
847
|
+
const expectedOutcome = normalizeString(
|
|
848
|
+
source.expected_outcome
|
|
849
|
+
|| source.expected
|
|
850
|
+
|| source.success_criteria
|
|
851
|
+
|| context.verification_plan
|
|
852
|
+
|| (context.scene_id ? `Scene ${context.scene_id} reaches deterministic verification gates.` : '')
|
|
853
|
+
);
|
|
854
|
+
const reproductionSteps = normalizeChainList(
|
|
855
|
+
source.reproduction_steps || source.repro_steps || source.steps,
|
|
856
|
+
20
|
|
857
|
+
);
|
|
858
|
+
const fallbackRepro = reproductionSteps.length > 0
|
|
859
|
+
? reproductionSteps
|
|
860
|
+
: [
|
|
861
|
+
normalizeString(context.goal) || 'Reproduce the reported issue in the target scene.',
|
|
862
|
+
'Capture logs and gate evidence for the failing path.'
|
|
863
|
+
].filter(Boolean);
|
|
864
|
+
const forbiddenWorkarounds = normalizeChainList(
|
|
865
|
+
source.forbidden_workarounds || source.prohibited_workarounds || source.disallowed_workarounds,
|
|
866
|
+
20
|
|
867
|
+
);
|
|
868
|
+
const fallbackForbidden = forbiddenWorkarounds.length > 0
|
|
869
|
+
? forbiddenWorkarounds
|
|
870
|
+
: [
|
|
871
|
+
'Do not bypass gates or tests.',
|
|
872
|
+
'Do not silence runtime errors.'
|
|
873
|
+
];
|
|
874
|
+
|
|
875
|
+
return {
|
|
876
|
+
issue_statement: issueStatement,
|
|
877
|
+
expected_outcome: expectedOutcome,
|
|
878
|
+
reproduction_steps: fallbackRepro,
|
|
879
|
+
impact_scope: normalizeString(source.impact_scope || source.scope || context.scene_id),
|
|
880
|
+
forbidden_workarounds: fallbackForbidden
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function extractGovernanceBreachSignals(report = {}) {
|
|
885
|
+
if (!report || typeof report !== 'object') {
|
|
886
|
+
return {
|
|
887
|
+
available: false,
|
|
888
|
+
high_breach_count: 0,
|
|
889
|
+
medium_breach_count: 0
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
const alerts = Array.isArray(report.alerts) ? report.alerts : [];
|
|
893
|
+
let highBreachCount = 0;
|
|
894
|
+
let mediumBreachCount = 0;
|
|
895
|
+
for (const alert of alerts) {
|
|
896
|
+
const status = normalizeString(alert && alert.status).toLowerCase();
|
|
897
|
+
const severity = normalizeString(alert && alert.severity).toLowerCase();
|
|
898
|
+
if (status !== 'breach') {
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
if (severity === 'high') {
|
|
902
|
+
highBreachCount += 1;
|
|
903
|
+
} else if (severity === 'medium') {
|
|
904
|
+
mediumBreachCount += 1;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return {
|
|
908
|
+
available: true,
|
|
909
|
+
high_breach_count: highBreachCount,
|
|
910
|
+
medium_breach_count: mediumBreachCount
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
|
|
727
914
|
function summarizeDomainChain(payload = {}) {
|
|
728
915
|
const ontology = payload && typeof payload.ontology === 'object' ? payload.ontology : {};
|
|
916
|
+
const ontologyEvidence = payload && typeof payload.ontology_evidence === 'object' ? payload.ontology_evidence : {};
|
|
729
917
|
const decisionPath = Array.isArray(payload.decision_execution_path) ? payload.decision_execution_path : [];
|
|
730
918
|
const correctionLoop = payload && typeof payload.correction_loop === 'object' ? payload.correction_loop : {};
|
|
731
919
|
const verification = payload && typeof payload.verification === 'object' ? payload.verification : {};
|
|
732
920
|
const hypotheses = Array.isArray(payload.hypotheses) ? payload.hypotheses : [];
|
|
733
921
|
const risks = Array.isArray(payload.risks) ? payload.risks : [];
|
|
922
|
+
const evidenceBindingCount = (
|
|
923
|
+
normalizeChainList(ontologyEvidence.entity, 50).length
|
|
924
|
+
+ normalizeChainList(ontologyEvidence.relation, 50).length
|
|
925
|
+
+ normalizeChainList(ontologyEvidence.business_rule, 50).length
|
|
926
|
+
+ normalizeChainList(ontologyEvidence.decision_policy, 50).length
|
|
927
|
+
+ normalizeChainList(ontologyEvidence.execution_flow, 50).length
|
|
928
|
+
);
|
|
734
929
|
|
|
735
930
|
return {
|
|
736
931
|
scene_id: normalizeString(payload.scene_id) || null,
|
|
@@ -746,6 +941,8 @@ function summarizeDomainChain(payload = {}) {
|
|
|
746
941
|
hypothesis_count: hypotheses.length,
|
|
747
942
|
risk_count: risks.length,
|
|
748
943
|
decision_path_steps: decisionPath.length,
|
|
944
|
+
evidence_binding_count: evidenceBindingCount,
|
|
945
|
+
verification_plan: normalizeString(verification.plan) || null,
|
|
749
946
|
correction_loop: {
|
|
750
947
|
triggers: normalizeChainList(correctionLoop.triggers, 5),
|
|
751
948
|
actions: normalizeChainList(correctionLoop.actions, 5)
|
|
@@ -780,7 +977,13 @@ function buildDomainChainRuntimeContext(payload = {}) {
|
|
|
780
977
|
verification: {
|
|
781
978
|
plan: normalizeString(payload?.verification?.plan) || null,
|
|
782
979
|
gates: normalizeChainList(payload?.verification?.gates, 10)
|
|
783
|
-
}
|
|
980
|
+
},
|
|
981
|
+
problem_contract: normalizeProblemContract(payload?.problem_contract || {}, {
|
|
982
|
+
scene_id: normalizeString(payload.scene_id) || '',
|
|
983
|
+
goal: normalizeString(payload?.problem?.statement) || '',
|
|
984
|
+
problem_statement: normalizeString(payload?.problem?.statement) || '',
|
|
985
|
+
verification_plan: normalizeString(payload?.verification?.plan) || ''
|
|
986
|
+
})
|
|
784
987
|
};
|
|
785
988
|
}
|
|
786
989
|
|
|
@@ -833,12 +1036,22 @@ async function resolveDomainChainBinding(options = {}, dependencies = {}) {
|
|
|
833
1036
|
problemStatement: goal || `Studio scene cycle for ${sceneId}`
|
|
834
1037
|
});
|
|
835
1038
|
const chain = await readSpecDomainChain(projectPath, explicitSpec, fileSystem);
|
|
1039
|
+
const problemContract = await readSpecProblemContract(projectPath, explicitSpec, fileSystem);
|
|
836
1040
|
if (!chain) {
|
|
837
1041
|
return {
|
|
838
1042
|
resolved: false,
|
|
839
1043
|
source: 'explicit-spec',
|
|
840
1044
|
spec_id: explicitSpec,
|
|
841
|
-
reason: 'domain_chain_missing'
|
|
1045
|
+
reason: 'domain_chain_missing',
|
|
1046
|
+
problem_contract: problemContract
|
|
1047
|
+
? normalizeProblemContract(problemContract.payload, {
|
|
1048
|
+
scene_id: sceneId,
|
|
1049
|
+
goal
|
|
1050
|
+
})
|
|
1051
|
+
: normalizeProblemContract({}, {
|
|
1052
|
+
scene_id: sceneId,
|
|
1053
|
+
goal
|
|
1054
|
+
})
|
|
842
1055
|
};
|
|
843
1056
|
}
|
|
844
1057
|
return {
|
|
@@ -848,7 +1061,17 @@ async function resolveDomainChainBinding(options = {}, dependencies = {}) {
|
|
|
848
1061
|
chain_path: chain.chain_path,
|
|
849
1062
|
updated_at: chain.updated_at,
|
|
850
1063
|
summary: summarizeDomainChain(chain.payload),
|
|
851
|
-
context: buildDomainChainRuntimeContext(chain.payload)
|
|
1064
|
+
context: buildDomainChainRuntimeContext(chain.payload),
|
|
1065
|
+
problem_contract: normalizeProblemContract(
|
|
1066
|
+
problemContract && problemContract.payload ? problemContract.payload : chain.payload?.problem_contract || {},
|
|
1067
|
+
{
|
|
1068
|
+
scene_id: sceneId,
|
|
1069
|
+
goal,
|
|
1070
|
+
problem_statement: normalizeString(chain?.payload?.problem?.statement),
|
|
1071
|
+
verification_plan: normalizeString(chain?.payload?.verification?.plan)
|
|
1072
|
+
}
|
|
1073
|
+
),
|
|
1074
|
+
problem_contract_path: problemContract ? problemContract.contract_path : null
|
|
852
1075
|
};
|
|
853
1076
|
}
|
|
854
1077
|
|
|
@@ -872,6 +1095,7 @@ async function resolveDomainChainBinding(options = {}, dependencies = {}) {
|
|
|
872
1095
|
}
|
|
873
1096
|
|
|
874
1097
|
const selected = candidates[0];
|
|
1098
|
+
const selectedContract = await readSpecProblemContract(projectPath, selected.spec_id, fileSystem);
|
|
875
1099
|
return {
|
|
876
1100
|
resolved: true,
|
|
877
1101
|
source: candidates.length === 1 ? 'scene-auto-single' : 'scene-auto-latest',
|
|
@@ -885,7 +1109,17 @@ async function resolveDomainChainBinding(options = {}, dependencies = {}) {
|
|
|
885
1109
|
updated_at: item.updated_at
|
|
886
1110
|
})),
|
|
887
1111
|
summary: summarizeDomainChain(selected.payload),
|
|
888
|
-
context: buildDomainChainRuntimeContext(selected.payload)
|
|
1112
|
+
context: buildDomainChainRuntimeContext(selected.payload),
|
|
1113
|
+
problem_contract: normalizeProblemContract(
|
|
1114
|
+
selectedContract && selectedContract.payload ? selectedContract.payload : selected.payload?.problem_contract || {},
|
|
1115
|
+
{
|
|
1116
|
+
scene_id: sceneId,
|
|
1117
|
+
goal,
|
|
1118
|
+
problem_statement: normalizeString(selected?.payload?.problem?.statement),
|
|
1119
|
+
verification_plan: normalizeString(selected?.payload?.verification?.plan)
|
|
1120
|
+
}
|
|
1121
|
+
),
|
|
1122
|
+
problem_contract_path: selectedContract ? selectedContract.contract_path : null
|
|
889
1123
|
};
|
|
890
1124
|
}
|
|
891
1125
|
|
|
@@ -948,6 +1182,14 @@ function buildJobDomainChainMetadata(job = {}) {
|
|
|
948
1182
|
: null;
|
|
949
1183
|
const summary = domainChain && domainChain.summary ? domainChain.summary : null;
|
|
950
1184
|
const context = domainChain && domainChain.context ? domainChain.context : null;
|
|
1185
|
+
const problemContract = job?.source?.problem_contract && typeof job.source.problem_contract === 'object'
|
|
1186
|
+
? job.source.problem_contract
|
|
1187
|
+
: normalizeProblemContract(context && context.problem_contract ? context.problem_contract : {}, {
|
|
1188
|
+
scene_id: normalizeString(job?.scene?.id),
|
|
1189
|
+
goal: normalizeString(job?.source?.goal),
|
|
1190
|
+
problem_statement: normalizeString(summary && summary.problem_statement),
|
|
1191
|
+
verification_plan: normalizeString(summary && summary.verification_plan)
|
|
1192
|
+
});
|
|
951
1193
|
return {
|
|
952
1194
|
resolved: domainChain && domainChain.resolved === true,
|
|
953
1195
|
source: domainChain && domainChain.source ? domainChain.source : 'none',
|
|
@@ -956,17 +1198,145 @@ function buildJobDomainChainMetadata(job = {}) {
|
|
|
956
1198
|
reason: domainChain && domainChain.reason ? domainChain.reason : null,
|
|
957
1199
|
decision_path_steps: summary ? Number(summary.decision_path_steps || 0) : 0,
|
|
958
1200
|
risk_count: summary ? Number(summary.risk_count || 0) : 0,
|
|
1201
|
+
evidence_binding_count: summary ? Number(summary.evidence_binding_count || 0) : 0,
|
|
959
1202
|
correction_triggers: summary && summary.correction_loop
|
|
960
1203
|
? normalizeChainList(summary.correction_loop.triggers, 10)
|
|
961
1204
|
: [],
|
|
962
1205
|
verification_gates: summary
|
|
963
1206
|
? normalizeChainList(summary.verification_gates, 10)
|
|
964
1207
|
: [],
|
|
1208
|
+
problem_contract: problemContract,
|
|
965
1209
|
summary: summary || null,
|
|
966
1210
|
context: context || null
|
|
967
1211
|
};
|
|
968
1212
|
}
|
|
969
1213
|
|
|
1214
|
+
function summarizeProblemEvaluation(evaluation = {}) {
|
|
1215
|
+
return {
|
|
1216
|
+
passed: evaluation.passed === true,
|
|
1217
|
+
blocked: evaluation.blocked === true,
|
|
1218
|
+
confidence_score: Number(evaluation.confidence_score || 0),
|
|
1219
|
+
risk_level: normalizeString(evaluation?.dimensions?.risk?.level) || 'low',
|
|
1220
|
+
strategy: normalizeString(evaluation?.dimensions?.strategy?.strategy) || 'direct-execution',
|
|
1221
|
+
contract_score: Number(evaluation?.dimensions?.problem_contract?.score || 0),
|
|
1222
|
+
ontology_score: Number(evaluation?.dimensions?.ontology_alignment?.score || 0),
|
|
1223
|
+
convergence_score: Number(evaluation?.dimensions?.convergence?.score || 0),
|
|
1224
|
+
contract_missing: Array.isArray(evaluation?.dimensions?.problem_contract?.missing)
|
|
1225
|
+
? evaluation.dimensions.problem_contract.missing
|
|
1226
|
+
: [],
|
|
1227
|
+
ontology_missing_axes: Array.isArray(evaluation?.dimensions?.ontology_alignment?.missing_axes)
|
|
1228
|
+
? evaluation.dimensions.ontology_alignment.missing_axes
|
|
1229
|
+
: [],
|
|
1230
|
+
convergence_missing: Array.isArray(evaluation?.dimensions?.convergence?.missing)
|
|
1231
|
+
? evaluation.dimensions.convergence.missing
|
|
1232
|
+
: [],
|
|
1233
|
+
blockers: Array.isArray(evaluation.blockers) ? evaluation.blockers : [],
|
|
1234
|
+
warnings: Array.isArray(evaluation.warnings) ? evaluation.warnings : [],
|
|
1235
|
+
recommendations: Array.isArray(evaluation.recommendations) ? evaluation.recommendations : [],
|
|
1236
|
+
report_file: normalizeString(evaluation.report_file) || null
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function deriveGateSignals(steps = []) {
|
|
1241
|
+
const normalized = Array.isArray(steps) ? steps : [];
|
|
1242
|
+
const requiredTotal = normalized.filter((step) => step && step.required !== false).length;
|
|
1243
|
+
const requiredEnabled = normalized.filter((step) => step && step.required !== false && step.enabled !== false).length;
|
|
1244
|
+
return {
|
|
1245
|
+
required_total: requiredTotal,
|
|
1246
|
+
required_enabled: requiredEnabled,
|
|
1247
|
+
required_missing: Math.max(0, requiredTotal - requiredEnabled)
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
function buildStageReadiness(job = {}, stage = '', overrides = {}) {
|
|
1252
|
+
const normalizedStage = normalizeString(stage).toLowerCase();
|
|
1253
|
+
const patchBundleReady = normalizeString(job?.artifacts?.patch_bundle_id).length > 0;
|
|
1254
|
+
const verifyReportReady = normalizeString(job?.artifacts?.verify_report).length > 0;
|
|
1255
|
+
const readiness = {
|
|
1256
|
+
prerequisites_ready: true,
|
|
1257
|
+
rollback_ready: isStageCompleted(job, 'apply'),
|
|
1258
|
+
patch_bundle_ready: patchBundleReady,
|
|
1259
|
+
verify_report_ready: verifyReportReady
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
if (normalizedStage === 'generate') {
|
|
1263
|
+
readiness.prerequisites_ready = isStageCompleted(job, 'plan');
|
|
1264
|
+
} else if (normalizedStage === 'apply') {
|
|
1265
|
+
readiness.prerequisites_ready = isStageCompleted(job, 'generate');
|
|
1266
|
+
} else if (normalizedStage === 'verify') {
|
|
1267
|
+
readiness.prerequisites_ready = isStageCompleted(job, 'apply');
|
|
1268
|
+
} else if (normalizedStage === 'release') {
|
|
1269
|
+
readiness.prerequisites_ready = isStageCompleted(job, 'verify');
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return {
|
|
1273
|
+
...readiness,
|
|
1274
|
+
...overrides
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function assignProblemEvalArtifact(job = {}, stage = '', evaluation = {}) {
|
|
1279
|
+
const normalizedStage = normalizeString(stage).toLowerCase();
|
|
1280
|
+
if (!normalizedStage) {
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
job.artifacts = job.artifacts || {};
|
|
1284
|
+
const reports = job.artifacts.problem_eval_reports && typeof job.artifacts.problem_eval_reports === 'object'
|
|
1285
|
+
? job.artifacts.problem_eval_reports
|
|
1286
|
+
: {};
|
|
1287
|
+
reports[normalizedStage] = normalizeString(evaluation.report_file) || null;
|
|
1288
|
+
job.artifacts.problem_eval_reports = reports;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
async function enforceProblemEvaluationForStage(job = {}, stage = '', context = {}, dependencies = {}) {
|
|
1292
|
+
const projectPath = dependencies.projectPath || process.cwd();
|
|
1293
|
+
const fileSystem = dependencies.fileSystem || fs;
|
|
1294
|
+
const evaluation = await runProblemEvaluation({
|
|
1295
|
+
stage,
|
|
1296
|
+
job_id: normalizeString(job.job_id),
|
|
1297
|
+
scene_id: normalizeString(context.scene_id || job?.scene?.id),
|
|
1298
|
+
spec_id: normalizeString(context.spec_id || job?.source?.spec_id || job?.scene?.spec_id),
|
|
1299
|
+
goal: normalizeString(context.goal || job?.source?.goal),
|
|
1300
|
+
release_channel: normalizeString(context.release_channel || ''),
|
|
1301
|
+
domain_chain: context.domain_chain || (job?.source?.domain_chain || {}),
|
|
1302
|
+
problem_contract: context.problem_contract || job?.source?.problem_contract || {},
|
|
1303
|
+
related_specs_count: Number(context.related_specs_count || job?.source?.related_specs?.total_candidates || 0),
|
|
1304
|
+
stage_readiness: context.stage_readiness || buildStageReadiness(job, stage),
|
|
1305
|
+
gate_signals: context.gate_signals || {}
|
|
1306
|
+
}, {
|
|
1307
|
+
projectPath,
|
|
1308
|
+
fileSystem,
|
|
1309
|
+
env: dependencies.env,
|
|
1310
|
+
writeReport: true
|
|
1311
|
+
});
|
|
1312
|
+
assignProblemEvalArtifact(job, stage, evaluation);
|
|
1313
|
+
return evaluation;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
async function markStudioStageBlockedByProblemEval(paths, job, stageName, evaluation, fileSystem = fs) {
|
|
1317
|
+
const summary = summarizeProblemEvaluation(evaluation);
|
|
1318
|
+
job.status = `${stageName}_blocked`;
|
|
1319
|
+
job.updated_at = nowIso();
|
|
1320
|
+
job.stages = job.stages || createStageState();
|
|
1321
|
+
job.stages[stageName] = {
|
|
1322
|
+
status: 'blocked',
|
|
1323
|
+
completed_at: null,
|
|
1324
|
+
metadata: {
|
|
1325
|
+
problem_evaluation: summary
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
await saveJob(paths, job, fileSystem);
|
|
1329
|
+
await appendStudioEvent(paths, job, `stage.${stageName}.blocked`, {
|
|
1330
|
+
problem_evaluation: summary
|
|
1331
|
+
}, fileSystem);
|
|
1332
|
+
await writeLatestJob(paths, job.job_id, fileSystem);
|
|
1333
|
+
|
|
1334
|
+
const reason = summary.blockers.length > 0
|
|
1335
|
+
? summary.blockers.join(', ')
|
|
1336
|
+
: 'problem-evaluation-policy';
|
|
1337
|
+
throw new Error(`studio ${stageName} blocked by problem evaluation: ${reason}`);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
970
1340
|
async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
971
1341
|
const projectPath = dependencies.projectPath || process.cwd();
|
|
972
1342
|
const fileSystem = dependencies.fileSystem || fs;
|
|
@@ -1013,6 +1383,63 @@ async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
|
1013
1383
|
|
|
1014
1384
|
const jobId = normalizeString(options.job) || createJobId();
|
|
1015
1385
|
const now = nowIso();
|
|
1386
|
+
const problemContract = normalizeProblemContract(
|
|
1387
|
+
domainChainBinding.problem_contract || {},
|
|
1388
|
+
{
|
|
1389
|
+
scene_id: sceneId,
|
|
1390
|
+
goal: normalizeString(options.goal),
|
|
1391
|
+
problem_statement: normalizeString(domainChainBinding?.summary?.problem_statement),
|
|
1392
|
+
verification_plan: normalizeString(domainChainBinding?.summary?.verification_plan)
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
const planShadowJob = {
|
|
1396
|
+
job_id: jobId,
|
|
1397
|
+
scene: {
|
|
1398
|
+
id: sceneId,
|
|
1399
|
+
spec_id: domainChainBinding.spec_id || specId || null
|
|
1400
|
+
},
|
|
1401
|
+
source: {
|
|
1402
|
+
goal: normalizeString(options.goal) || null,
|
|
1403
|
+
spec_id: domainChainBinding.spec_id || specId || null,
|
|
1404
|
+
problem_contract: problemContract,
|
|
1405
|
+
problem_contract_path: domainChainBinding.problem_contract_path || null,
|
|
1406
|
+
domain_chain: {
|
|
1407
|
+
resolved: domainChainBinding.resolved === true,
|
|
1408
|
+
summary: domainChainBinding.summary || null
|
|
1409
|
+
},
|
|
1410
|
+
related_specs: {
|
|
1411
|
+
total_candidates: Number(relatedSpecLookup.total_candidates || 0)
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1414
|
+
artifacts: {}
|
|
1415
|
+
};
|
|
1416
|
+
const planProblemEvaluation = await enforceProblemEvaluationForStage(planShadowJob, 'plan', {
|
|
1417
|
+
scene_id: sceneId,
|
|
1418
|
+
spec_id: domainChainBinding.spec_id || specId || null,
|
|
1419
|
+
goal: normalizeString(options.goal) || null,
|
|
1420
|
+
problem_contract: problemContract,
|
|
1421
|
+
domain_chain: {
|
|
1422
|
+
resolved: domainChainBinding.resolved === true,
|
|
1423
|
+
summary: domainChainBinding.summary || null
|
|
1424
|
+
},
|
|
1425
|
+
related_specs_count: Number(relatedSpecLookup.total_candidates || 0),
|
|
1426
|
+
stage_readiness: {
|
|
1427
|
+
prerequisites_ready: true,
|
|
1428
|
+
rollback_ready: false,
|
|
1429
|
+
patch_bundle_ready: false,
|
|
1430
|
+
verify_report_ready: false
|
|
1431
|
+
}
|
|
1432
|
+
}, {
|
|
1433
|
+
projectPath,
|
|
1434
|
+
fileSystem,
|
|
1435
|
+
env: dependencies.env
|
|
1436
|
+
});
|
|
1437
|
+
if (!planProblemEvaluation.passed) {
|
|
1438
|
+
const blockers = Array.isArray(planProblemEvaluation.blockers) && planProblemEvaluation.blockers.length > 0
|
|
1439
|
+
? planProblemEvaluation.blockers.join(', ')
|
|
1440
|
+
: 'problem-evaluation-policy';
|
|
1441
|
+
throw new Error(`studio plan blocked by problem evaluation: ${blockers}`);
|
|
1442
|
+
}
|
|
1016
1443
|
const stages = createStageState();
|
|
1017
1444
|
const sessionStore = dependencies.sessionStore || new SessionStore(projectPath);
|
|
1018
1445
|
const sceneSessionBinding = await sessionStore.beginSceneSession({
|
|
@@ -1035,6 +1462,8 @@ async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
|
1035
1462
|
domain_chain_path: domainChainBinding.chain_path || null,
|
|
1036
1463
|
domain_chain_summary: domainChainBinding.summary || null,
|
|
1037
1464
|
domain_chain_reason: domainChainBinding.reason || null,
|
|
1465
|
+
problem_contract: problemContract,
|
|
1466
|
+
problem_evaluation: summarizeProblemEvaluation(planProblemEvaluation),
|
|
1038
1467
|
related_specs_total: Number(relatedSpecLookup.total_candidates || 0),
|
|
1039
1468
|
related_specs_top: relatedSpecItems
|
|
1040
1469
|
}
|
|
@@ -1050,6 +1479,8 @@ async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
|
1050
1479
|
from_chat: fromChat,
|
|
1051
1480
|
goal: normalizeString(options.goal) || null,
|
|
1052
1481
|
spec_id: domainChainBinding.spec_id || specId || null,
|
|
1482
|
+
problem_contract: problemContract,
|
|
1483
|
+
problem_contract_path: domainChainBinding.problem_contract_path || null,
|
|
1053
1484
|
domain_chain: {
|
|
1054
1485
|
resolved: domainChainBinding.resolved === true,
|
|
1055
1486
|
source: domainChainBinding.source || 'none',
|
|
@@ -1088,7 +1519,10 @@ async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
|
1088
1519
|
artifacts: {
|
|
1089
1520
|
patch_bundle_id: null,
|
|
1090
1521
|
verify_report: null,
|
|
1091
|
-
release_ref: null
|
|
1522
|
+
release_ref: null,
|
|
1523
|
+
problem_eval_reports: {
|
|
1524
|
+
plan: normalizeString(planProblemEvaluation.report_file) || null
|
|
1525
|
+
}
|
|
1092
1526
|
}
|
|
1093
1527
|
};
|
|
1094
1528
|
|
|
@@ -1104,6 +1538,8 @@ async function runStudioPlanCommand(options = {}, dependencies = {}) {
|
|
|
1104
1538
|
domain_chain_source: domainChainBinding.source || 'none',
|
|
1105
1539
|
domain_chain_spec_id: domainChainBinding.spec_id || null,
|
|
1106
1540
|
domain_chain_path: domainChainBinding.chain_path || null,
|
|
1541
|
+
problem_contract: problemContract,
|
|
1542
|
+
problem_evaluation: summarizeProblemEvaluation(planProblemEvaluation),
|
|
1107
1543
|
related_specs_total: Number(relatedSpecLookup.total_candidates || 0),
|
|
1108
1544
|
related_spec_ids: relatedSpecItems.map((item) => item.spec_id)
|
|
1109
1545
|
}, fileSystem);
|
|
@@ -1138,6 +1574,21 @@ async function runStudioGenerateCommand(options = {}, dependencies = {}) {
|
|
|
1138
1574
|
throw new Error(`Scene mismatch: planned scene is "${jobSceneId}" but --scene provided "${sceneArg}"`);
|
|
1139
1575
|
}
|
|
1140
1576
|
const sceneId = sceneArg || jobSceneId;
|
|
1577
|
+
const generateProblemEvaluation = await enforceProblemEvaluationForStage(job, 'generate', {
|
|
1578
|
+
scene_id: sceneId,
|
|
1579
|
+
spec_id: normalizeString(job?.source?.spec_id) || normalizeString(job?.scene?.spec_id) || null,
|
|
1580
|
+
goal: normalizeString(job?.source?.goal),
|
|
1581
|
+
domain_chain: job?.source?.domain_chain || {},
|
|
1582
|
+
related_specs_count: Number(job?.source?.related_specs?.total_candidates || 0),
|
|
1583
|
+
stage_readiness: buildStageReadiness(job, 'generate')
|
|
1584
|
+
}, {
|
|
1585
|
+
projectPath,
|
|
1586
|
+
fileSystem,
|
|
1587
|
+
env: dependencies.env
|
|
1588
|
+
});
|
|
1589
|
+
if (!generateProblemEvaluation.passed) {
|
|
1590
|
+
await markStudioStageBlockedByProblemEval(paths, job, 'generate', generateProblemEvaluation, fileSystem);
|
|
1591
|
+
}
|
|
1141
1592
|
const patchBundleId = normalizeString(options.patchBundle) || `patch-${sceneId}-${Date.now()}`;
|
|
1142
1593
|
const domainChainMetadata = buildJobDomainChainMetadata(job);
|
|
1143
1594
|
const generateReportPath = `${STUDIO_REPORTS_DIR}/generate-${job.job_id}.json`;
|
|
@@ -1167,6 +1618,7 @@ async function runStudioGenerateCommand(options = {}, dependencies = {}) {
|
|
|
1167
1618
|
scene_id: sceneId,
|
|
1168
1619
|
target: job.target,
|
|
1169
1620
|
patch_bundle_id: patchBundleId,
|
|
1621
|
+
problem_evaluation: summarizeProblemEvaluation(generateProblemEvaluation),
|
|
1170
1622
|
domain_chain: domainChainMetadata,
|
|
1171
1623
|
report: generateReportPath
|
|
1172
1624
|
});
|
|
@@ -1176,6 +1628,7 @@ async function runStudioGenerateCommand(options = {}, dependencies = {}) {
|
|
|
1176
1628
|
scene_id: sceneId,
|
|
1177
1629
|
target: job.target,
|
|
1178
1630
|
patch_bundle_id: patchBundleId,
|
|
1631
|
+
problem_evaluation: summarizeProblemEvaluation(generateProblemEvaluation),
|
|
1179
1632
|
domain_chain: domainChainMetadata,
|
|
1180
1633
|
report: generateReportPath
|
|
1181
1634
|
}, fileSystem);
|
|
@@ -1211,6 +1664,23 @@ async function runStudioApplyCommand(options = {}, dependencies = {}) {
|
|
|
1211
1664
|
if (!patchBundleId) {
|
|
1212
1665
|
throw new Error('--patch-bundle is required (or generate stage must provide one)');
|
|
1213
1666
|
}
|
|
1667
|
+
const applyProblemEvaluation = await enforceProblemEvaluationForStage(job, 'apply', {
|
|
1668
|
+
scene_id: normalizeString(job?.scene?.id),
|
|
1669
|
+
spec_id: normalizeString(job?.source?.spec_id) || normalizeString(job?.scene?.spec_id) || null,
|
|
1670
|
+
goal: normalizeString(job?.source?.goal),
|
|
1671
|
+
domain_chain: job?.source?.domain_chain || {},
|
|
1672
|
+
related_specs_count: Number(job?.source?.related_specs?.total_candidates || 0),
|
|
1673
|
+
stage_readiness: buildStageReadiness(job, 'apply', {
|
|
1674
|
+
patch_bundle_ready: normalizeString(patchBundleId).length > 0
|
|
1675
|
+
})
|
|
1676
|
+
}, {
|
|
1677
|
+
projectPath,
|
|
1678
|
+
fileSystem,
|
|
1679
|
+
env: dependencies.env
|
|
1680
|
+
});
|
|
1681
|
+
if (!applyProblemEvaluation.passed) {
|
|
1682
|
+
await markStudioStageBlockedByProblemEval(paths, job, 'apply', applyProblemEvaluation, fileSystem);
|
|
1683
|
+
}
|
|
1214
1684
|
|
|
1215
1685
|
job.status = 'applied';
|
|
1216
1686
|
job.artifacts = job.artifacts || {};
|
|
@@ -1219,13 +1689,15 @@ async function runStudioApplyCommand(options = {}, dependencies = {}) {
|
|
|
1219
1689
|
|
|
1220
1690
|
ensureStageCompleted(job, 'apply', {
|
|
1221
1691
|
patch_bundle_id: patchBundleId,
|
|
1222
|
-
auth_required: authResult.required
|
|
1692
|
+
auth_required: authResult.required,
|
|
1693
|
+
problem_evaluation: summarizeProblemEvaluation(applyProblemEvaluation)
|
|
1223
1694
|
});
|
|
1224
1695
|
|
|
1225
1696
|
await saveJob(paths, job, fileSystem);
|
|
1226
1697
|
await appendStudioEvent(paths, job, 'stage.apply.completed', {
|
|
1227
1698
|
patch_bundle_id: patchBundleId,
|
|
1228
|
-
auth_required: authResult.required
|
|
1699
|
+
auth_required: authResult.required,
|
|
1700
|
+
problem_evaluation: summarizeProblemEvaluation(applyProblemEvaluation)
|
|
1229
1701
|
}, fileSystem);
|
|
1230
1702
|
await writeLatestJob(paths, jobId, fileSystem);
|
|
1231
1703
|
|
|
@@ -1257,8 +1729,29 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1257
1729
|
const autoErrorbookRecords = [];
|
|
1258
1730
|
const gateSteps = await buildVerifyGateSteps({ profile }, {
|
|
1259
1731
|
projectPath,
|
|
1260
|
-
fileSystem
|
|
1732
|
+
fileSystem,
|
|
1733
|
+
specId: normalizeString(domainChainMetadata.spec_id) || null
|
|
1734
|
+
});
|
|
1735
|
+
const verifyProblemEvaluation = await enforceProblemEvaluationForStage(job, 'verify', {
|
|
1736
|
+
scene_id: normalizeString(job?.scene?.id),
|
|
1737
|
+
spec_id: normalizeString(domainChainMetadata.spec_id) || normalizeString(job?.source?.spec_id),
|
|
1738
|
+
goal: normalizeString(job?.source?.goal),
|
|
1739
|
+
domain_chain: job?.source?.domain_chain || {},
|
|
1740
|
+
problem_contract: job?.source?.problem_contract || {},
|
|
1741
|
+
related_specs_count: Number(job?.source?.related_specs?.total_candidates || 0),
|
|
1742
|
+
stage_readiness: buildStageReadiness(job, 'verify', {
|
|
1743
|
+
gate_required_ready: deriveGateSignals(gateSteps).required_missing === 0,
|
|
1744
|
+
convergence_strict: profile === 'strict'
|
|
1745
|
+
}),
|
|
1746
|
+
gate_signals: deriveGateSignals(gateSteps)
|
|
1747
|
+
}, {
|
|
1748
|
+
projectPath,
|
|
1749
|
+
fileSystem,
|
|
1750
|
+
env: dependencies.env
|
|
1261
1751
|
});
|
|
1752
|
+
if (!verifyProblemEvaluation.passed) {
|
|
1753
|
+
await markStudioStageBlockedByProblemEval(paths, job, 'verify', verifyProblemEvaluation, fileSystem);
|
|
1754
|
+
}
|
|
1262
1755
|
const gateResult = await executeGateSteps(gateSteps, {
|
|
1263
1756
|
projectPath,
|
|
1264
1757
|
commandRunner: dependencies.commandRunner,
|
|
@@ -1296,6 +1789,7 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1296
1789
|
passed: gateResult.passed,
|
|
1297
1790
|
steps: gateResult.steps,
|
|
1298
1791
|
domain_chain: domainChainMetadata,
|
|
1792
|
+
problem_evaluation: summarizeProblemEvaluation(verifyProblemEvaluation),
|
|
1299
1793
|
auto_errorbook_records: autoErrorbookRecords
|
|
1300
1794
|
};
|
|
1301
1795
|
|
|
@@ -1314,6 +1808,7 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1314
1808
|
profile,
|
|
1315
1809
|
passed: false,
|
|
1316
1810
|
report: verifyReportPath,
|
|
1811
|
+
problem_evaluation: summarizeProblemEvaluation(verifyProblemEvaluation),
|
|
1317
1812
|
domain_chain: domainChainMetadata,
|
|
1318
1813
|
auto_errorbook_records: autoErrorbookRecords
|
|
1319
1814
|
}
|
|
@@ -1322,6 +1817,7 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1322
1817
|
await appendStudioEvent(paths, job, 'stage.verify.failed', {
|
|
1323
1818
|
profile,
|
|
1324
1819
|
report: verifyReportPath,
|
|
1820
|
+
problem_evaluation: summarizeProblemEvaluation(verifyProblemEvaluation),
|
|
1325
1821
|
domain_chain: domainChainMetadata,
|
|
1326
1822
|
auto_errorbook_records: autoErrorbookRecords
|
|
1327
1823
|
}, fileSystem);
|
|
@@ -1334,6 +1830,7 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1334
1830
|
profile,
|
|
1335
1831
|
passed: true,
|
|
1336
1832
|
report: verifyReportPath,
|
|
1833
|
+
problem_evaluation: summarizeProblemEvaluation(verifyProblemEvaluation),
|
|
1337
1834
|
domain_chain: domainChainMetadata,
|
|
1338
1835
|
auto_errorbook_records: autoErrorbookRecords
|
|
1339
1836
|
});
|
|
@@ -1343,6 +1840,7 @@ async function runStudioVerifyCommand(options = {}, dependencies = {}) {
|
|
|
1343
1840
|
profile,
|
|
1344
1841
|
passed: true,
|
|
1345
1842
|
report: verifyReportPath,
|
|
1843
|
+
problem_evaluation: summarizeProblemEvaluation(verifyProblemEvaluation),
|
|
1346
1844
|
domain_chain: domainChainMetadata,
|
|
1347
1845
|
auto_errorbook_records: autoErrorbookRecords
|
|
1348
1846
|
}, fileSystem);
|
|
@@ -1386,10 +1884,46 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1386
1884
|
const releaseStartedAt = nowIso();
|
|
1387
1885
|
const domainChainMetadata = buildJobDomainChainMetadata(job);
|
|
1388
1886
|
const autoErrorbookRecords = [];
|
|
1389
|
-
const
|
|
1887
|
+
const verifyReportSignals = await readVerifyReportSignals(
|
|
1390
1888
|
projectPath,
|
|
1889
|
+
normalizeString(job?.artifacts?.verify_report),
|
|
1391
1890
|
fileSystem
|
|
1891
|
+
);
|
|
1892
|
+
const governanceSignals = await readGovernanceSignals(projectPath, fileSystem);
|
|
1893
|
+
const gateSteps = await buildReleaseGateSteps({ profile }, {
|
|
1894
|
+
projectPath,
|
|
1895
|
+
fileSystem,
|
|
1896
|
+
specId: normalizeString(domainChainMetadata.spec_id) || null,
|
|
1897
|
+
verifyReportPath: normalizeString(job?.artifacts?.verify_report) || null
|
|
1392
1898
|
});
|
|
1899
|
+
const releaseGateSignals = deriveGateSignals(gateSteps);
|
|
1900
|
+
const releaseProblemEvaluation = await enforceProblemEvaluationForStage(job, 'release', {
|
|
1901
|
+
scene_id: normalizeString(job?.scene?.id),
|
|
1902
|
+
spec_id: normalizeString(domainChainMetadata.spec_id) || normalizeString(job?.source?.spec_id),
|
|
1903
|
+
goal: normalizeString(job?.source?.goal),
|
|
1904
|
+
release_channel: channel,
|
|
1905
|
+
domain_chain: job?.source?.domain_chain || {},
|
|
1906
|
+
problem_contract: job?.source?.problem_contract || {},
|
|
1907
|
+
related_specs_count: Number(job?.source?.related_specs?.total_candidates || 0),
|
|
1908
|
+
stage_readiness: buildStageReadiness(job, 'release', {
|
|
1909
|
+
gate_required_ready: releaseGateSignals.required_missing === 0,
|
|
1910
|
+
convergence_strict: profile === 'strict',
|
|
1911
|
+
verify_stage_passed: isStageCompleted(job, 'verify'),
|
|
1912
|
+
verify_report_ready: verifyReportSignals.available,
|
|
1913
|
+
verify_report_passed: verifyReportSignals.passed,
|
|
1914
|
+
regression_passed: verifyReportSignals.passed && verifyReportSignals.failed_step_count === 0,
|
|
1915
|
+
governance_report_ready: governanceSignals.available,
|
|
1916
|
+
high_alert_count: Number(governanceSignals.high_breach_count || 0)
|
|
1917
|
+
}),
|
|
1918
|
+
gate_signals: releaseGateSignals
|
|
1919
|
+
}, {
|
|
1920
|
+
projectPath,
|
|
1921
|
+
fileSystem,
|
|
1922
|
+
env: dependencies.env
|
|
1923
|
+
});
|
|
1924
|
+
if (!releaseProblemEvaluation.passed) {
|
|
1925
|
+
await markStudioStageBlockedByProblemEval(paths, job, 'release', releaseProblemEvaluation, fileSystem);
|
|
1926
|
+
}
|
|
1393
1927
|
const gateResult = await executeGateSteps(gateSteps, {
|
|
1394
1928
|
projectPath,
|
|
1395
1929
|
commandRunner: dependencies.commandRunner,
|
|
@@ -1429,6 +1963,9 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1429
1963
|
passed: gateResult.passed,
|
|
1430
1964
|
steps: gateResult.steps,
|
|
1431
1965
|
domain_chain: domainChainMetadata,
|
|
1966
|
+
verify_signals: verifyReportSignals,
|
|
1967
|
+
governance_signals: governanceSignals,
|
|
1968
|
+
problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
|
|
1432
1969
|
auto_errorbook_records: autoErrorbookRecords
|
|
1433
1970
|
};
|
|
1434
1971
|
|
|
@@ -1450,6 +1987,7 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1450
1987
|
passed: false,
|
|
1451
1988
|
report: releaseReportPath,
|
|
1452
1989
|
auth_required: authResult.required,
|
|
1990
|
+
problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
|
|
1453
1991
|
domain_chain: domainChainMetadata,
|
|
1454
1992
|
auto_errorbook_records: autoErrorbookRecords
|
|
1455
1993
|
}
|
|
@@ -1460,6 +1998,7 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1460
1998
|
release_ref: releaseRef,
|
|
1461
1999
|
report: releaseReportPath,
|
|
1462
2000
|
auth_required: authResult.required,
|
|
2001
|
+
problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
|
|
1463
2002
|
domain_chain: domainChainMetadata,
|
|
1464
2003
|
auto_errorbook_records: autoErrorbookRecords
|
|
1465
2004
|
}, fileSystem);
|
|
@@ -1473,6 +2012,7 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1473
2012
|
release_ref: releaseRef,
|
|
1474
2013
|
report: releaseReportPath,
|
|
1475
2014
|
auth_required: authResult.required,
|
|
2015
|
+
problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
|
|
1476
2016
|
domain_chain: domainChainMetadata,
|
|
1477
2017
|
auto_errorbook_records: autoErrorbookRecords
|
|
1478
2018
|
});
|
|
@@ -1504,6 +2044,7 @@ async function runStudioReleaseCommand(options = {}, dependencies = {}) {
|
|
|
1504
2044
|
release_ref: releaseRef,
|
|
1505
2045
|
report: releaseReportPath,
|
|
1506
2046
|
auth_required: authResult.required,
|
|
2047
|
+
problem_evaluation: summarizeProblemEvaluation(releaseProblemEvaluation),
|
|
1507
2048
|
domain_chain: domainChainMetadata,
|
|
1508
2049
|
auto_errorbook_records: autoErrorbookRecords
|
|
1509
2050
|
}, fileSystem);
|