Skip to content

Architecture

The architectural requirements. The live, generated architecture overview renders the current state from the module docstrings at every build; this chapter states the rules that state must obey.

The layered pipeline

Dependencies flow strictly downward; no module imports upward:

post   qa          engineering data | probe and regression evidence
run    workspace   headless execution | input library, run layout, manifest
cases              simulation and campaign definitions
script results     validating script builder | output parsers
commands           the evidence-backed per-version command database
versions           canonical version identifiers and ordering
_atmosphere        the standard atmosphere, importing only the base exception below it
_errors            the package base exception, imported by every layer and importing none

The bottom two rows are not pipeline stages. _errors defines the package base exception and the refusals more than one layer names, and it imports nothing from this package, so every layer above may import it without a cycle. _atmosphere holds the standard atmosphere and imports only _errors; it is a floor for the same reason, that it needs no layer above it and any of them may import it, and nothing flows THROUGH either.

The claim is stated that way deliberately. An architect pass found an earlier wording asserting that "several layers need it" while, at the time, only the exception catalog imported anything from it. Today the workspace layer's flight-condition resolver imports it as well. What makes it a floor is the DIRECTION, which is checkable, rather than a count of consumers, which changes. They are the floor the stack stands on rather than steps in it, which is why the arrow chains that state the flow name six rows and this table names eight.

Side branches follow the same downward-only rule: fsi (the structural side of the aeroelastic loop), probes and farfield (survey lattices and conservation ledgers), and the presentation layer (reference, overview).

Architectural rules

AD-01 Downward dependencies only

A module may import only from layers below its own. Upward imports are forbidden; where an upper-layer entry point is exposed from a lower-layer module for user convenience, the import is deferred and documented, and introducing a cycle is a defect.

AD-02 Single rendering sources

Anything presented in two places is rendered from one source: the command reference and compatibility matrix from the database, the architecture overview from the module docstrings, the docs example pages from the example scripts. Nothing generated is committed.

One stated exception, and its condition: reports/requirements-index.json IS generated and committed, because its consumer is a dashboard outside this repository that cannot run a generator here and reads the file directly. The condition that makes it safe is that a Tier 1 test regenerates and compares, and a second test sweeps the SRS independently so a parser miss cannot pass as a clean regeneration. An exception without that pair is the staleness this decision exists to prevent.

AD-03 No global mutable state

Script construction and every other stateful operation happen on objects; two scripts, two campaigns, or two workspaces never interfere through module state (PP-2).

AD-04 Explicit inputs, never guessed

FlightStream version and executable path are explicit inputs of a campaign. Nothing is read from environment variables or guessed from the filesystem.

AD-05 Optional heavy dependencies behind extras

The core runtime set stays minimal; NFR-06 is its single home and this decision does not restate it. Structural analysis ([fsi]), geometry gating ([geom]), manual reading for the maintainer tool ([manual], licence card reports/RPT-017_manual-extra-license_2026-08-04.md), and plotting ([plot]) are optional extras with license evidence recorded before adoption; a missing extra fails with the didactic install hint, never an ImportError traceback.

AD-06 One substrate for results (restated 2026-07-27)

Tabular results and multidimensional labeled fields rest on one substrate (glossary): the sister library's structures over NumPy. pandas and xarray leave the runtime set.

This decision previously read "tables are pandas; multidimensional labeled fields are xarray, and the two never substitute". The reference decision of 2026-07-27 does not adapt that reading, it invalidates it: the package stops carrying its own table and labeled-field stack. The old text is recorded here rather than deleted, because a decision that changes content is only readable against what it replaced.

Transition, stated because the code and this decision do not yet agree. pandas and xarray are still declared and still imported at three sites in src/ (results/tables.py, farfield/__init__.py, post/writers.py, with the test suite as a fourth surface), and they stayed through v0.5.0, which shipped without the migration; the removal release number is NFR-06's to state and is unset, that release number being stated by NFR-06 as its home of record. There is no deprecation cycle in between and that is deliberate: NFR-20 governs from 1.0, so a consumer finds out on upgrade. The accepted cost is stated in the decision record, not softened here.

Who "a consumer" means is worth naming, because the shorthand for this decision has been "the tidy table" (glossary) and that is the smaller half. farfield carries xarray in the SIGNATURES of its public ledger functions, so a rotor or far-field user is affected exactly as much as a table user. The changelog notice states both.

AD-07 ITACA as a core dependency (2026-07-23, restated 2026-07-27)

pyflightstream and ITACA are sister libraries by the same author, born integrated: each may generate requirements for the other, and each documents awareness of the other's architecture (see the sister library page). ITACA stays solver-agnostic and never imports pyflightstream (its DD-22 and DD-23 record the same seam from the other side), so anything crossing the seam takes generic arrays and never FlightStream probes.

What changed on 2026-07-27: ITACA was a future optional [itaca] extra and becomes a core runtime dependency, because AD-06 now rests on it. Two things follow that are easy to get wrong.

  • This is a creation, not a promotion. No [itaca] extra has ever existed here; the string does not appear in pyproject.toml. A review pass that asserted otherwise was wrong.
  • The dependency's own metadata propagates to ours: its version pin form and its requires-python ceiling are governed by NFR-22, which is their single home.

The direction is not a change of direction. The sister already recorded that this driver's pandas and xarray usage migrates to it; what changed is the pace and the granularity, from per structure to one move.

Command-line surface

Five console entry points, one per operational concern: pyfs-qa (evidence tiers 2 and 3), pyfs-workspace (workspace initialization, archiving of a recorded simulation, and migration of a flat geometry library into one folder per geometry), pyfs-matrix (run-matrix upgrade, conversion, pre-flight, run, boundary inventory, collection of a submitted job's outputs, and post-processing; submission is not a command of its own, it is what run does on Linux with a cluster profile), pyfs-fsi (the coupling-loop executable), and pyfs-manual (reading a vendor manual against the command database, and WRITING documented version rows back into it from that reading; maintainer tooling outside the run pipeline). CLIs are thin argument layers over the public Python API; execution paths always require the explicit executable. The registration transaction is pyflightstream.utils.database, not the argument parser, for that reason: it is the second writer into the evidence authority and it owes the guards the first one has.