@@ -12,7 +12,8 @@ import {
1212 listFeatures ,
1313 type FeatureData ,
1414 type Manifold ,
15- type Constraint
15+ type Constraint ,
16+ type Evidence
1617} from '../lib/parser.js' ;
1718import { countConstraints , countConstraintsByType } from '../lib/schema.js' ;
1819import {
@@ -23,11 +24,19 @@ import {
2324 style ,
2425 toJSON
2526} from '../lib/output.js' ;
27+ import {
28+ verifyAllEvidence ,
29+ normalizeEvidence ,
30+ formatVerificationReport ,
31+ type VerificationReport
32+ } from '../lib/evidence.js' ;
2633
2734interface VerifyOptions {
2835 json ?: boolean ;
2936 artifacts ?: boolean ;
3037 strict ?: boolean ;
38+ verifyEvidence ?: boolean ;
39+ runTests ?: boolean ;
3140}
3241
3342interface ArtifactVerification {
@@ -53,6 +62,7 @@ interface VerificationResult {
5362 requiredTruthsSatisfied : number ;
5463 percentage : number ;
5564 } ;
65+ evidence ?: VerificationReport ;
5666 issues : string [ ] ;
5767}
5868
@@ -66,6 +76,8 @@ export function registerVerifyCommand(program: Command): void {
6676 . option ( '--json' , 'Output as JSON' )
6777 . option ( '--artifacts' , 'Verify generated artifacts exist' )
6878 . option ( '--strict' , 'Require all artifacts and coverage' )
79+ . option ( '--verify-evidence' , 'Verify concrete evidence for required truths (v3)' )
80+ . option ( '--run-tests' , 'Execute test evidence verification (requires --verify-evidence)' )
6981 . action ( async ( feature : string | undefined , options : VerifyOptions ) => {
7082 const exitCode = await verifyCommand ( feature , options ) ;
7183 process . exit ( exitCode ) ;
@@ -217,6 +229,23 @@ async function verifyFeature(
217229 }
218230 }
219231
232+ // Verify concrete evidence (v3 feature)
233+ if ( options . verifyEvidence ) {
234+ const projectRoot = dirname ( manifoldDir ) ;
235+ const evidenceReport = await verifyEvidenceForFeature ( manifold , projectRoot , options ) ;
236+ result . evidence = evidenceReport ;
237+
238+ if ( evidenceReport . failed > 0 ) {
239+ issues . push ( `${ evidenceReport . failed } evidence item(s) failed verification` ) ;
240+ result . result = options . strict ? 'FAIL' : 'PARTIAL' ;
241+ }
242+
243+ if ( evidenceReport . pending > 0 && options . strict ) {
244+ issues . push ( `${ evidenceReport . pending } evidence item(s) pending` ) ;
245+ result . result = 'PARTIAL' ;
246+ }
247+ }
248+
220249 // Phase check for strict mode
221250 if ( options . strict && manifold . phase !== 'VERIFIED' ) {
222251 issues . push ( `Phase is ${ manifold . phase } , expected VERIFIED` ) ;
@@ -315,6 +344,42 @@ function calculateCoverage(manifold: Manifold): NonNullable<VerificationResult['
315344 } ;
316345}
317346
347+ /**
348+ * Verify concrete evidence for required truths (v3 feature)
349+ * Satisfies: Phase A - Reality Grounding
350+ */
351+ async function verifyEvidenceForFeature (
352+ manifold : Manifold ,
353+ projectRoot : string ,
354+ options : VerifyOptions
355+ ) : Promise < VerificationReport > {
356+ // Collect all evidence from required truths
357+ const allEvidence : Evidence [ ] = [ ] ;
358+
359+ const requiredTruths = manifold . anchors ?. required_truths ?? [ ] ;
360+ for ( const rt of requiredTruths ) {
361+ const evidence = normalizeEvidence ( rt . evidence ) ;
362+ allEvidence . push ( ...evidence ) ;
363+ }
364+
365+ // Also collect evidence from constraints (v3)
366+ const constraintCategories = [ 'business' , 'technical' , 'user_experience' , 'security' , 'operational' ] as const ;
367+ for ( const category of constraintCategories ) {
368+ const constraints = manifold . constraints ?. [ category ] ?? [ ] ;
369+ for ( const constraint of constraints ) {
370+ if ( constraint . verified_by ) {
371+ allEvidence . push ( ...constraint . verified_by ) ;
372+ }
373+ }
374+ }
375+
376+ // Verify all evidence
377+ return verifyAllEvidence ( allEvidence , {
378+ runTests : options . runTests ,
379+ projectRoot
380+ } ) ;
381+ }
382+
318383/**
319384 * Print verification output to console
320385 */
@@ -363,6 +428,26 @@ function printVerificationOutput(result: VerificationResult, options: VerifyOpti
363428 }
364429 }
365430
431+ // Evidence (v3)
432+ if ( result . evidence ) {
433+ const e = result . evidence ;
434+ const evidenceStatus = e . failed === 0
435+ ? style . success ( `${ e . verified } /${ e . total } verified` )
436+ : style . warning ( `${ e . verified } /${ e . total } verified, ${ e . failed } failed` ) ;
437+
438+ println ( formatKeyValue ( 'Evidence' , evidenceStatus ) ) ;
439+
440+ // Show detailed evidence results
441+ if ( ( e . failed > 0 || e . pending > 0 ) && ! options . json ) {
442+ println ( ) ;
443+ for ( const r of e . results ) {
444+ const icon = r . passed ? '✓' : r . evidence . status === 'PENDING' ? '⏳' : '✗' ;
445+ const colorFn = r . passed ? style . success : r . evidence . status === 'PENDING' ? style . dim : style . error ;
446+ println ( ` ${ colorFn ( icon ) } [${ r . evidence . type } ] ${ r . message } ` ) ;
447+ }
448+ }
449+ }
450+
366451 // Issues
367452 if ( result . issues . length > 0 ) {
368453 println ( ) ;
0 commit comments