@@ -410,16 +410,7 @@ They should follow the same pattern as everything else.
410410** Value** : Analysis phase works on immutable merged data, returns immutable results.
411411Can be parallelized, memoized, reordered.
412412
413- ** Changes** :
414- - [ ] ` solve_deadness : config -> merged_view -> analysis_result ` (pure)
415- - [ ] Input ` merged_view ` is immutable (from Tasks 4-7)
416- - [ ] Output ` analysis_result ` is immutable
417- - [ ] ` Decl.report ` : Return ` issue ` instead of logging
418- - [ ] Remove all ` Log_.warning ` , ` Log_.item ` calls from analysis path
419- - [ ] Side effects (logging, JSON) only in final reporting phase
420- - [ ] Make ` DeadModules ` state part of ` analysis_result ` (currently mutated during solver)
421-
422- ** Architecture** :
413+ ** Architecture goal** :
423414```
424415merged_view (immutable)
425416 │
@@ -433,12 +424,127 @@ analysis_result (immutable)
433424report (side effects here only)
434425```
435426
436- ** Key guarantee** : After Tasks 4-7, the analysis phase has ** no mutable state** .
437- This enables parallelization, caching, and incremental recomputation.
427+ ** Approach** : Break into small, behavior-preserving steps. Each step can be verified
428+ before moving to the next. The key is: change return type, then immediately log at
429+ the call site, so behavior stays identical.
430+
431+ ---
432+
433+ #### Task 8.1: Create ` AnalysisResult ` module ✅
434+
435+ ** Changes** :
436+ - [x] Create ` AnalysisResult.ml/mli ` with ` type t = { issues: Common.issue list } `
437+ - [x] Add constructors: ` empty ` , ` add_issue ` , ` get_issues `
438+ - [x] Add issue constructors: ` make_dead_issue ` , ` make_dead_module_issue `
439+
440+ ** Verify** : Build succeeds. No behavior change (module not used yet).
441+
442+ ---
443+
444+ #### Task 8.2: Make ` emitWarning ` return issue (behavior preserving) ✅
445+
446+ ** Changes** :
447+ - [x] Add ` makeDeadIssue ` (pure function)
448+ - [x] ` emitWarning ` uses ` makeDeadIssue ` internally (later removed)
449+
450+ ** Verify** : ` make test-analysis ` passes with identical output.
451+
452+ ---
453+
454+ #### Task 8.3: Make ` Decl.report ` return issue option (behavior preserving) ✅
455+
456+ ** Changes** :
457+ - [x] Change ` Decl.report ` signature to return ` issue option `
458+ - [x] Use ` makeDeadIssue ` internally
459+ - [x] At call site in ` reportDead ` , log returned issue
460+
461+ ** Verify** : ` make test-analysis ` passes with identical output.
462+
463+ ---
464+
465+ #### Task 8.4: Make ` DeadOptionalArgs.check ` return issues (behavior preserving) ✅
466+
467+ ** Changes** :
468+ - [x] Add ` foldUnused ` , ` foldAlwaysUsed ` to ` OptionalArgs ` module
469+ - [x] Change ` check ` signature to return ` issue list ` instead of ` unit `
470+ - [x] At call site in ` resolveRecursiveRefs ` , immediately log returned issues
471+
472+ ** Verify** : ` make test-analysis ` passes with identical output.
473+
474+ ---
475+
476+ #### Task 8.5: Collect incorrect annotation issues (behavior preserving) ✅
477+
478+ ** Changes** :
479+ - [x] Use ` makeDeadIssue ` for incorrect ` @dead ` annotation issues
480+ - [x] Log immediately at call site
481+ - [x] Remove ` emitWarning ` function (no longer needed)
482+
483+ ** Verify** : ` make test-analysis ` passes with identical output.
438484
439- ** Test** : Run analysis twice on same input, verify identical results. Verify no side effects.
485+ ---
486+
487+ #### Task 8.6: Make ` DeadModules.checkModuleDead ` return issue (behavior preserving) ✅
488+
489+ ** Changes** :
490+ - [x] Change ` DeadModules.checkModuleDead ` to return ` issue option `
491+ - [x] At call sites, log returned issue immediately
492+
493+ ** Verify** : ` make test-analysis ` passes with identical output.
494+
495+ ---
496+
497+ #### Task 8.7: Collect all issues in ` reportDead ` (behavior preserving) ✅
498+
499+ ** Changes** :
500+ - [x] Change ` Decl.report ` to return ` issue list ` (includes dead module issues)
501+ - [x] Use ` List.concat_map ` to collect all issues
502+ - [x] Log all issues at the end of ` reportDead `
503+
504+ ** Verify** : ` make test-analysis ` passes with identical output.
505+
506+ ---
507+
508+ #### Task 8.8: Return ` AnalysisResult.t ` from ` reportDead ` ✅
509+
510+ ** Changes** :
511+ - [x] Change ` reportDead ` to return ` AnalysisResult.t ` instead of ` unit `
512+ - [x] Move logging from ` reportDead ` to caller in ` Reanalyze.ml `
513+
514+ ** Verify** : ` make test-analysis ` passes with identical output.
515+
516+ ---
517+
518+ ** Status** : Complete ✅
519+
520+ ** Key guarantee** : The analysis phase (` reportDead ` ) now returns an immutable
521+ ` AnalysisResult.t ` containing all dead code issues. Side effects (logging)
522+ only happen in the caller (` Reanalyze.runAnalysis ` ).
523+
524+ ** Note** : Optional args and incorrect annotation issues were logged inline
525+ during ` resolveRecursiveRefs ` . Fixed in Task 8b.
526+
527+ ### Task 8b: Collect all issues in AnalysisResult.t (P5) ✅
528+
529+ ** Value** : Complete the pure analysis phase - all issues returned in result, no inline logging.
530+
531+ ** Problem** : ` resolveRecursiveRefs ` was logging two types of issues inline:
532+ 1 . Optional args issues (from ` checkOptionalArgFn ` )
533+ 2 . Incorrect ` @dead ` annotation issues
534+
535+ These bypassed ` AnalysisResult.t ` and were logged directly via ` Log_.warning ` .
536+
537+ ** Changes** :
538+ - [x] Pass ` ~issues:(Common.issue list ref) ` through ` resolveRecursiveRefs `
539+ - [x] Collect optional args issues instead of logging inline
540+ - [x] Collect incorrect annotation issues instead of logging inline
541+ - [x] Add collected issues to ` AnalysisResult.t ` in ` reportDead `
542+ - [x] Remove all ` Log_.warning ` calls from ` resolveRecursiveRefs `
543+
544+ ** Status** : Complete ✅
440545
441- ** Estimated effort** : Medium (many logging call sites, but mechanical)
546+ ** Key guarantee** : No ` Log_.warning ` calls in ` resolveRecursiveRefs ` . All issues
547+ are collected in ` AnalysisResult.t ` and logged by the caller.
442548
443549### Task 9: ~~ Separate annotation computation from file writing (P5)~~ REMOVED
444550
0 commit comments