Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/acdeveloper-sci/forti4d/llms.txt

Use this file to discover all available pages before exploring further.

Forti4D produces more than thirty output files, but making sense of them does not require reading every CSV at once. The pipeline is deliberately layered: a summary HTML report provides the fastest entry point, a ranked prioritization CSV surfaces what matters most, and the consolidated table answers every detailed question. This guide walks through each layer in the order you should approach it, explains what the scores and labels mean, and highlights the patterns that most frequently indicate migration risk.

Where to Start

1

Open report.html

Open <FORT_OUT>/report.html in a browser. It is a fully self-contained file — no internet connection required. The top of the page shows a priority summary: one card per tier (CRITICAL / HIGH / MEDIUM / LOW / DEAD_CODE / TOTAL) with unit counts and percentages. This gives you an instant sense of the corpus risk profile before looking at any individual unit.Below the summary is the main unit table — filterable by tier, sortable by any column. Use the filter buttons to focus on one tier at a time.
2

Review report_prioritization.csv

report_prioritization.csv is the authoritative ranked list. It sorts units by tier and then by composite score descending within each tier. For each unit it shows the five per-component scores (Score_CC, Score_FanIn, Score_Legacy, Score_Clon, Score_E4) so you can see why a unit received its overall score — useful when calibrating effort estimates.
3

Drill into report_consolidated.csv

report_consolidated.csv has one row per unit and 34 columns covering every metric produced by the pipeline. Open it in a spreadsheet, sort and filter, and add computed columns (such as CC × Fan_In) to surface the specific risk patterns described below.
4

Render a call graph for context

Metric tables tell you what but not where. Render graph_simple.dot (or a per-entry-point subgraph) with Graphviz to see the dependency structure at a glance. The graph is especially useful for understanding why a high-Fan-In unit is risky and which executables share the most dependencies.

Migration Risk Tiers

prioritization.py assigns every unit to one of five tiers based on a composite score from 0 to 100. Dead code is separated from the scoring scale and always appears last.
TierScoreWhat it means
CRITICAL≥ 40High complexity or criticality. Requires early planning — changes here carry the highest risk of regression.
HIGH≥ 25Significant risk in at least one dimension. Plan carefully before modifying.
MEDIUM≥ 12Moderate risk. Schedule for migration but not urgent.
LOW< 12Low risk. Straightforward to migrate or rewrite.
DEAD_CODEUNREACHABLE from any entry point. Evaluate for deletion before migrating.
Start your triage with DEAD_CODE. Confirmed dead units can often be removed entirely, which shrinks the analysis surface before you address anything else. See the reachability section below for caveats.

Risk Score Components

The composite score is a weighted sum across five signals. Each component is normalized to 0–1 before weighting; the final score is multiplied by 100.
Score = (W_CC × CC_norm + W_FAN_IN × FanIn_norm + W_LEGACY × Legacy_norm
       + W_CLONE × Clone_norm + W_E4 × E4_norm) × 100

Cyclomatic Complexity — 30%

Weight: 0.30McCabe CC counts the number of linearly independent paths through a unit. Normalized against the 95th percentile of CC among reachable units (not the maximum) to prevent a single outlier from compressing the scale.
CC rangeLevel
1–10LOW
11–20MEDIUM
21–50HIGH
> 50CRITICAL
Caveat: a high CC in a large SELECT CASE dispatcher is mechanically complex but structurally simple. Confirm with Pct_Control in the density columns — if control statements dominate and Fan_Out is low, the unit is a dispatcher, not a tangled algorithm.

Fan-In Criticality — 30%

Weight: 0.30Fan-In counts how many other units call or USE this one. High Fan-In means the unit is widely reused — any change propagates risk to all callers. Normalized against the 95th percentile of Fan-In among reachable units.
Fan-InRisk
0Not called — dead code or entry point
1–4Low coupling
5–9Moderate — review before changing
≥ 10High — treat as core infrastructure
The most dangerous combination is high CC + high Fan-In: complex logic that many callers depend on. Sort report_consolidated.csv by CC × Fan_In descending to surface these “core knots.”

Legacy Density — 20%

Weight: 0.20Pct_Legacy measures the proportion of statements classified as legacy constructs: COMMON blocks, GOTO, EQUIVALENCE, and IMPLICIT (non-NONE) statements. Normalization is direct: Pct_Legacy / 100.Units with high legacy density that are also widely called (Fan_In > 3) are the riskiest to modify — any change must account for global state, implicit typing, and memory aliasing simultaneously.

Clone State — 15%

Weight: 0.15Clone penalty based on the worst clone state among all pairs involving the unit.
Clone statePenalty
DIVERGED1.0 (full penalty)
SIMILAR0.5
IDENTICAL0.25
None0.0
A DIVERGED pair is the most dangerous: the same unit name exists in multiple files but the implementations have drifted apart. Callers may be linked to either version depending on the build configuration.

E4 Scope Risk — 5%

Weight: 0.05Flags two scope-level hazards that make safe migration harder:
  • No IMPLICIT NONE (0.70 of the component): default Fortran typing is active. Undeclared variables may exist; any rename or extraction can silently change types.
  • EQUIVALENCE aliasing (0.30 of the component): two or more variables share the same memory address, breaking type inference and making it unsafe to reorder or rename variables without full alias analysis.
A unit with neither IMPLICIT NONE nor EQUIVALENCE receives the full component score.
The component weights (0.30 / 0.30 / 0.20 / 0.15 / 0.05) and tier thresholds (40 / 25 / 12) are project-defined values calibrated for typical Fortran legacy corpora. If the score distribution is too concentrated in one tier, adjust W_CC, W_FAN_IN, THRESH_CRITICAL, etc. in prioritization.py.

Migration Strategies

cross_analysis.py assigns each unit one of seven recommended strategies based on two composite indices:
  • IVC (Calculation Value Index): equals Pct_Calc. How much of the unit is pure algorithmic computation.
  • ICM (Migration Complexity Index): combines control-flow density, legacy density, Fan-Out, Fan-In, and an optional E4 penalty for missing IMPLICIT NONE or the presence of EQUIVALENCE.
Rules are evaluated in order; the first match wins.
StrategyConditionRecommended action
ELIMINATEReachability_Status = UNREACHABLEConfirmed dead code. Review and delete.
ANALYZE_UTILITYFan-In = 0 (no reachability data)Not called — verify whether truly unused, then delete or document.
DIRECT_MIGRATIONIVC > 50 and ICM < 30Pure algorithm, low coupling. Translate directly to the target language.
REPLACE_LIBPct_IO > 30 or Pct_Decl > 40, and IVC < 20Infrastructure or boilerplate. Replace with a standard library call rather than translating line-by-line.
REFACTOR_COREICM > 25 and Fan-In > 5High-risk, high-dependency knot. Refactor the interfaces and reduce coupling before any migration begins.
REWRITE_ISOLATEDICM > 20Complex but low systemic impact. Rewrite from scratch in the target language; the limited callers make it feasible to swap.
STANDARD_MIGRATIONAll other connected unitsNormal migration — translate with standard practices.
REFACTOR_CORE units are the highest-planning items in the strategy table. Do not begin migrating them until their callers are mapped and interfaces are stabilized. Starting with DIRECT_MIGRATION units instead builds momentum and validates the migration toolchain on low-risk targets first.
In a standard full pipeline run, cross_analysis executes at step 6 — before reachability, symbols, and equivalences are available. The ELIMINATE rule and the E4 ICM penalty are therefore silently skipped on a first pass. Re-run cross analysis manually after the pipeline completes to apply the full rule engine:
forti4d --from cross_analysis --only cross_analysis

Structural Roles

structure_analysis.py classifies each source file into an architectural role based on its Fan-In/Fan-Out profile. This classification appears in report_structure_analysis.csv and is visible in the consolidated report.

CRITICAL_NODE

High Fan-In. Many other units depend on this file. It is the core library layer of the system. Changes here require thorough testing of all dependents before and after migration.

ORCHESTRATOR

High Fan-Out. This file coordinates many parts of the system. Orchestrators are hard to test in isolation because they depend on so many callees. Migrate their dependencies before migrating the orchestrator itself.

ENTRY_POINT

Contains a PROGRAM or IMPLICIT-MAIN unit. The executable roots of the corpus. Use these as the starting nodes for per-executable subgraph analysis (visual_graph.py --entry <name>).

WORKER

Moderate Fan-In and Fan-Out — a service routine. Workers are the bulk of most corpora and are typically the lowest-risk migration targets once CRITICAL_NODE dependencies are stabilized.

ISLAND

No connections — neither called nor calling anything in the corpus. May be a standalone utility program compiled separately, an old backup file, or genuine dead code. Confirm with dep_00_ambiguities.csv and report_reachability.csv.

MIXED

Both high Fan-In and high Fan-Out. Acts as both a core dependency and an orchestrator. These files sit at junctions in the call graph and deserve early attention in any migration plan.
Pattern: a large number of CRITICAL_NODE files with high Fan-In signals a shared utility layer — a set of routines called by almost everything else. These must be migrated (or wrapped) first, before any of their callers can move. Pattern: a large ISLAND count often means the corpus contains many standalone utility programs or historical backups that were never cleaned up. Check dep_00_ambiguities.csv to see if any island unit names also appear in other files.

Reachability and Dead Code

reachability.py performs a breadth-first search from all entry points (PROGRAM and IMPLICIT-MAIN units), following CALL, USE, and FUNC_CALL edges. Every unit is classified as:
StatusMeaning
ENTRY_POINTA PROGRAM or IMPLICIT-MAIN unit — the executable root.
REACHABLEReachable from at least one entry point.
UNREACHABLENot reachable from any entry point — dead code candidate.
Before deleting UNREACHABLE units, check for common false positives:
  • Alternative versions: files named *_old.f90, *_ori.f90, or * - Copie.f90 are often inactive fallbacks. Confirm with dep_00_ambiguities.csv — if the unit name appears in another file, it is a duplicate, not necessarily unused.
  • Utility executables: small programs in the same directory that are compiled separately and have no caller in the current corpus. Check report_structure_analysis.csv — if the file is classified as ISLAND, this is likely the case.
  • External entry points: units called from a Makefile, a shell script, or a test harness outside the analyzed directory.

Reading the Call Graph DOT Files

visual_graph.py produces Graphviz DOT files. Render them with:
# PNG for quick viewing
dot -Tpng results/graph_simple.dot -o results/graph_simple.png

# SVG for interactive zooming in a browser
dot -Tsvg results/graph_complete.dot -o results/graph_complete.svg

# Per-entry-point subgraph
dot -Tpng results/graph_mcdes.dot -o results/graph_mcdes.png

Node colors (reachability)

ColorHexMeaning
Blue#4472C4Entry point (PROGRAM / IMPLICIT-MAIN)
Green#70AD47Reachable unit
Grey#A6A6A6Dead code (UNREACHABLE)
Yellow#FFD966Reachable from multiple selected entry points (--entry ep1 ep2)

Node shapes (unit type)

ShapeUnit type
doubleoctagonPROGRAM, IMPLICIT-MAIN
hexagonMODULE
ellipseFUNCTION
diamondBLOCK_DATA
boxSUBROUTINE (and default)

Edge styles (dependency type)

StyleDependency
Solid blackCALL
Solid greenFUNC_CALL
Dashed blueUSE (module import)
Each node label shows unit_name, CC=<value>, and Fi=<Fan_In> when metadata is available. Nodes are grouped into clusters by source file. Useful graph queries:
  • Who calls this unit? Find the node in the graph, follow incoming edges back to callers.
  • What does this executable depend on? Run visual_graph.py --entry <name> — the resulting subgraph shows the full transitive dependency tree.
  • Do two executables share dependencies? Run visual_graph.py --entry ep1 ep2 — yellow nodes appear at every shared dependency, revealing the integration risk between the two programs.

Common Patterns and What They Signal

A cluster of CRITICAL-tier units all with high Fan-In points to a shared library layer used by most of the corpus. These units are the highest-risk change targets. Before migrating anything else, either migrate these units first (so callers can be updated to the new interface) or wrap them behind a stable adapter layer that both old and new code can call.
A high number of ISLAND files means the corpus contains many units that are not connected to the main call graph. This is common in scientific codebases that have accumulated standalone utilities, experimental programs, and historical copies. Audit each ISLAND against report_reachability.csv and dep_00_ambiguities.csv before deciding whether to migrate or delete.
Units with high Pct_Legacy (COMMON, GOTO, EQUIVALENCE) that are also widely called carry double risk: the legacy constructs create implicit global state or aliasing and any change propagates to many callers. Refactor these to use explicit interfaces (module variables or subroutine arguments) before any migration.
A DIVERGED clone pair means the same unit name exists in multiple files with drifted implementations. Which version is linked depends on the build configuration. This is a correctness risk before it is a migration risk — confirm with dep_00_ambiguities.csv which callers resolve to which copy.
Filter report_consolidated.csv for Pct_Legacy < 5%, Implicit_None = YES, and Fan_In < 3. These units are fully typed, contain almost no legacy constructs, and have few callers. They are the easiest to extract, test independently, and migrate first — ideal for validating your migration toolchain before tackling riskier units.

Build docs developers (and LLMs) love