Skip to main content

Documentation Index

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

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

ForTriage is structured as a layered Streamlit application. The architecture separates data acquisition (uploads), analysis (Forti4D pipeline), visualization (views), and AI summarization (Gemini adapter) into distinct modules with clear boundaries. No layer reaches across another’s boundary: views never invoke Forti4D, and the AI adapter never reads DataFrames directly.

Module Layout

fortriage/
├── app.py              # Entry point: navigation and session initialization
├── config.py           # All constants and configuration
├── pipeline.py         # Forti4D subprocess integration, PipelineResult
├── uploads.py          # Multi-mechanism file staging and validation
├── state.py            # Session state lifecycle (init, reset)
├── insights_context.py # PipelineResult → LLM-ready context aggregation
├── gemini_client.py    # Google Gemini provider adapter (only genai importer)
├── prompts.py          # Prompt file loader
├── views/
│   ├── overview.py         # Upload flow + results dashboard
│   ├── drilldown.py        # Per-unit metric detail
│   ├── executive_summary.py # PROJECT_SUMMARY.md renderer
│   ├── report_explorer.py  # Migration Strategy / Coupling / Clones tables
│   └── ai_insights.py      # AI Insights generation and chat
└── components/
    ├── badges.py       # Tier and reachability badge components
    ├── charts.py       # Altair chart builders
    ├── metric_bar.py   # Proportional metric bar component
    └── unit_modal.py   # Drill-down modal handoff
Each layer has a single, well-defined responsibility. config.py is the only file allowed to define constants. gemini_client.py is the only file allowed to import google.genai. pipeline.py is the only file allowed to invoke forti4d.

Data Flow

The end-to-end flow from file upload to AI-generated insights follows these steps:
1

File upload and staging

The user uploads Fortran source files via the Overview tab. uploads.py’s merge_upload_sources() normalizes direct file uploads and ZIP archives into a deduplicated list of StagedFile objects, enforcing extension allowlists and per-file size limits.
2

Pipeline invocation

On “Run analysis”, pipeline.py’s run_pipeline() copies staged files to a temporary directory (fortriage_src_*) and invokes Forti4D as a subprocess, pointing it at a second temp directory (fortriage_out_*) for outputs.
3

Output loading and cleanup

All six CSV and Markdown outputs are read into a PipelineResult dataclass while both temp directories are still live. After loading, the temp directories are deleted. PipelineResult holds everything in memory — no paths escape the dataclass.
4

Session state storage

PipelineResult is stored in st.session_state.pipeline_result. From this point, all views and AI modules read exclusively from session state — no further disk or subprocess access occurs.
5

Dashboard views

The Overview, Drill-down, Executive Summary, and Report Explorer views read their data from st.session_state.pipeline_result fields (prioritization, consolidated, migration_strategy, common_coupling, clones, project_summary).
6

AI Insights context aggregation

insights_context.build_insights_context() aggregates PipelineResult into a bounded, LLM-safe context dict — scalars, small dicts of counts, and capped lists of top-N items. Raw DataFrames are never sent to the model.
7

Gemini API call

gemini_client.generate_insights() sends the context dict to Gemini and returns structured JSON conforming to a response schema. The response is parsed and validated by insights_context.parse_insights_response().
8

Chat follow-up

Subsequent chat turns use insights_context.build_chat_context() to extend the insights context with drilldown summaries and the already-displayed insights text, then gemini_client.send_chat_message() for each turn.

Forti4D Boundary

ForTriage is a consumer of Forti4D — it never modifies the analysis engine, its configuration, or its outputs. The integration boundary is precisely pipeline.py. run_pipeline() is the only place in the entire codebase where forti4d is invoked. This constraint is intentional: it makes the backing implementation fully swappable without touching any downstream code. For example, the subprocess call could be replaced with an HTTP call to a cloud Lambda function, a Docker container, or a mock for testing — and no view, component, or AI module would require any change. Forti4D is installed as a Python package from its GitHub repository:
forti4d @ git+https://github.com/acdeveloper-sci/forti4d.git@v0.7.1
ForTriage intentionally does not expose Forti4D’s per-file diagnostic dumps (audit/, blocks/). Only the six curated, corpus-level reports are surfaced: report_prioritization.csv, report_consolidated.csv, report_migration_strategy.csv, common_coupling.csv, report_clones.csv, and PROJECT_SUMMARY.md.

Session State

state.py is the single source of truth for all st.session_state keys used by ForTriage. No module is permitted to write directly to session_state with ad-hoc keys.
FunctionDescription
init_session_state()Sets defaults for all session state keys. Idempotent — called on every Streamlit rerun. Only populates keys that don’t already exist, so live values are never overwritten on rerun.
reset_session_state()Overwrites all keys to their defaults. Triggered by the “New Analysis” button to return the app to its initial state.
Key session state fields:
KeyTypeDescription
pipeline_resultPipelineResult | NoneThe result of the most recent analysis run, or None before any analysis.
analysis_in_progressboolTrue while the background pipeline thread is running. Controls the spinner and disables the run button.
current_viewstrActive tab/view name for navigation state.
selected_unitstr | NoneUnit name currently open in the Drill-down modal, if any.
overview_filtersdictActive filter state for the Overview table — keys: search (text query), type (unit type filter), tier (tier filter).
excluded_filenamesset[str]Filenames removed from staging via the chip removal control. Cleared when the ZIP identity changes.
report_explorer_tabstrActive tab in the Report Explorer view (default: "migration_strategy").
last_run_completed_atdatetime | NoneTimestamp of the most recently completed analysis run, or None.
run_idstr | NoneUnique identifier for the current analysis run, used to key AI Insights results.
modal_unitstr | NoneUnit name for the currently open Drill-down modal (distinct from selected_unit for handoff coordination).
overview_table_reset_tokenintIncremented to signal the Overview table to reset scroll and selection state.
uploader_reset_tokenintIncremented to force a re-mount of the file uploader widget, clearing staged files.
last_zip_identitytuple[str, int] | None(name, size) identity of the last uploaded ZIP, used to detect when the ZIP changes and clear excluded_filenames.
sample_fixtures_loadedboolTrue after the “Load sample fixtures” button is clicked; cleared on reset.
ai_insights_resultInsightsSections | NoneParsed AI Insights response for the current analysis, or None if not yet generated.
ai_insights_kpisdict | NonePre-computed KPI dict for the current AI Insights run, or None.
ai_insights_errorstr | NoneError message from a failed AI Insights generation, or None on success. Exactly one of ai_insights_result / ai_insights_error is non-None after generation completes.
chat_contextdict | NonePre-built chat context dict (from build_chat_context()) for the current run, or None.
chat_historylist[dict]Ordered list of {"role": ..., "text": ...} dicts for the current chat session.

AI Insights Adapter Pattern

gemini_client.py is the only module in the project that imports google.genai. All other modules — views/ai_insights.py, insights_context.py, state.py — depend only on the two public function signatures and the two public types this module exposes:
SymbolKindDescription
generate_insights(context, config)FunctionSends the pre-aggregated context dict to Gemini and returns structured JSON text.
send_chat_message(context, history, user_message, config)FunctionSends a follow-up chat turn and returns the model’s free-text reply.
LLMConfigDataclassProvider credentials: api_key, model, timeout_seconds. Built by the caller from st.secretsgemini_client.py never reads secrets itself.
LLMErrorExceptionRaised for any SDK-level failure: auth errors, rate limits, timeouts, transport failures, or empty responses. All SDK exceptions are normalized to this single type.
This port/adapter pattern means the Google Gemini provider can be swapped for any other LLM provider by replacing gemini_client.py alone — the views, context aggregator, and session state require no changes.
LLMConfig is deliberately built by the Streamlit view layer (which has access to st.secrets) and passed into gemini_client.py — rather than having gemini_client.py read secrets directly. This keeps the adapter free of Streamlit imports and makes it testable without a Streamlit runtime.
AI Insights operates on aggregated metrics — not raw Fortran source code. When a user generates insights or sends a chat message, the context dict (scalars, counts, and bounded top-N unit summaries) is sent to Google’s Gemini API. Raw source code never leaves the analysis environment. Review Google’s data terms before using AI Insights on confidential codebases.

Build docs developers (and LLMs) love