Data Model Definitions

Thread Data Model: Core Definitions

Canonical reference for all Thread development — SDK, backend, onboarding, and agent-driven implementation. If a term is used in Thread, its meaning is defined here.

Version 0.3 · Updated March 2026 · Harry Smith, Director of Flight Sciences
Concept Map — click a node to jump to its section
owns contains contains captures snapshots bridges moves data feeds builds Project Branch Node Edge Provenance Commit Sync Merge Tracked Types SDK Operations Flow360 Workspaces Comments Saved Plots Search
01Project

A Project is the top-level container in Thread. It represents a single engineering endeavour — typically an aircraft programme, a propulsion system, or a research campaign.

A Project owns exactly one Main branch and may contain any number of additional Branches. All data in Thread belongs to exactly one Project. Projects have members with roles (owner, admin, editor, viewer) that control access and permissions.

A Project may contain one or more Configurations — named aircraft or vehicle variants (e.g., “Baseline”, “Extended Range”) with their own Design Conditions (reference quantities scoped to that variant).

Examples: “F-35 Aero Database”, “eVTOL Transition Study”, “Propeller Optimisation Campaign”

fct.connect(project_id="cessna-172")
fct.projects()
fct.use("new-project")
fct.create_project("name")
02Branch

A Branch is a named, versioned namespace for data within a Project. Every Node in Thread lives on exactly one Branch. Branches are the mechanism for parallel work, trade studies, and staged review.

Main

Main is the single source of truth for a Project. There is exactly one Main per Project, created automatically. When main protection is enabled, data reaches Main only through a Merge.

Named Branches

A named Branch is a shared, long-lived divergence from Main — a new revision, a trade study, a regulatory submission baseline. Branch creation is O(1) — copy-on-write, no data duplication.

Workspaces

A Workspace is a personal, server-side context for work before promoting to a shared Branch. Workspaces persist across Python sessions and support selective promotion via fct.promote().

fct.checkout("experiment")      # switch/create
fct.branches()                  # list all
fct.delete_branch("old-study")
fct.protect_main(True)
03Node

A Node is the atomic unit of data in Thread — a simulation result, input parameter, reference quantity, plot definition, cached function output, or tracked DataFrame.

Properties

UUID, project_id, branch, ltree path, kind, dtype, value storage (value_scalar / value_text / value_json), units, source, code_ref, vcs_ref, timestamps, and tombstone flag.

Immutability

Nodes are mutable in place, but every mutation is captured by a PostgreSQL trigger into nodes_history — the full audit trail.

Record Types

Node kind is an open string. Common kinds used across the SDK and backend:

KindSourceDescription
scalarSDKNamed scalar value (TrackedFloat/Int)
arraySDKTrackedArray data
dataframeSDKTrackedDataFrame / TrackedSeries row data
seriesSDKTrackedSeries column
metadataSDKCaptured metadata / decorator context
reference_quantityAPIOwned ref quantities (Sref, MAC, etc.)
saved_plotAPIPlot definitions with thumbnails
geometryFlow360Imported geometry
surface_meshFlow360Imported surface mesh
volume_meshFlow360Imported volume mesh
runFlow360 / SDKSolver run with inputs & outputs
04Edge

An Edge is a directed relationship between two Nodes in the provenance DAG. It records that one Node was derived from, depends on, or is related to another.

Properties: UUID, project_id, branch, parent_id, child_id, relationship (e.g., derived_from, input_to), operation, and metadata.

Edges are created automatically by the SDK’s tracked types. When a TrackedArray is multiplied by a TrackedFloat, the registry records an edge from both parents to the result.

05Commit

A Commit is a named, timestamped savepoint on a Branch. Created explicitly by the user, not automatically on sync. On protected Main, commits arrive only via merge.

Properties: UUID, project_id, branch, parent_ids (supports merge commits), message, author, snapshot_hash, and timestamp.

fct.commit("AOA sweep complete")
fct.log()
fct.log(branch="experiment")
06Provenance

Computational Provenance

Answers: “What process produced this data?” Captured automatically by tracked types. The provenance DAG traces outputs back to inputs through operations — user code runs unchanged.

Curatorial Provenance

Answers: “Who accepted this data and when?” Stored in Commits, Merges, and Merge Approvals. The combination of both is Thread’s core differentiator.

07Sync

Sync transfers the local provenance registry to the Thread backend — nodes, edges, figures, data exports, script analysis, cache entries, and tracked DataFrames.

Sync is idempotent — deterministic UUIDs from content hashes mean repeated syncs don’t duplicate. Orphan nodes are pruned before sync.

fct.sync()               # sync everything
fct.sync(tracked_obj)    # sync one object + ancestors
fct.push(obj, "name")    # sync and mark as saved
08Merge

Merge moves data from one Branch to another. With Merge Approvals, designated reviewers must approve individual node changes before merge proceeds.

fct.diff("main")
fct.merge(into="main")
fct.merge(source="experiment", into="main")
09Tracked Types & Local Provenance

Zero-Config Setup

from flexcomputethread import auto_setup
auto_setup()

df = pd.read_csv("forces.csv")   # TrackedDataFrame
cl = df['Cl'].values              # TrackedArray
plt.savefig("cl_polar.png")       # provenance embedded

Tracked Types

TypeBasePurpose
TrackedArraynumpy.ndarrayArray ops with provenance
TrackedDataFramepandas.DataFrameDataFrame ops with provenance
TrackedSeriespandas.SeriesSeries ops with provenance
TrackedFloatfloatScalar arithmetic with provenance
TrackedIntintInteger scalar with provenance
TrackedPolarsDataFramepolars.DataFramePolars tracking

Provenance Recovery

@fct.track — re-attaches lineage through untracked code. fct.attach() — manual. fct.scalar() — named DAG node. fct.recover() — float boundary recovery.

Health & Caching

fct.watcher detects provenance loss. fct.fix() rewrites source code to repair breaks. @fct.cached provides content-addressed caching with staleness detection. FunctionSurrogate / PipelineSurrogate for RBF gap-fill.

Capture & Figures

fct.capture() and fct.save_figure() capture matplotlib/plotly figures with full provenance. fct.read_provenance() extracts embedded lineage from saved images. DataRole and RoleBinding annotate data purpose.

Tracking Control

fct.stop_tracking() / fct.start_tracking() / fct.no_tracking() context manager — temporarily disable provenance when needed. fct.set_tracking_level() / fct.get_tracking_level() for granular control.

Multi-Fidelity & ADB

MultiFidelityModel and FidelityCascade blend results across solver fidelity levels (panel codes through high-fidelity CFD). AerodynamicDatabase with ParameterSpace, FidelityTier, and ADBEntry provides a structured aerodynamic database with gap detection.

from flexcomputethread import MultiFidelityModel, AerodynamicDatabase

model = MultiFidelityModel(fidelity_levels=FIDELITY_LEVELS)
adb = AerodynamicDatabase(parameter_space=ps)
10SDK Backend Operations
# Connection
fct.connect(project_id="cessna-172")
fct.use("cessna-172")          # alias
fct.use_or_create("new-proj")  # create if missing
fct.is_connected()

# Branch & Workspace
fct.checkout("experiment")
fct.branches()
fct.workspace()                # personal workspace
fct.protect_main(True)

# Versioning
fct.sync()
fct.commit("AOA sweep done")
fct.log()
fct.diff("main")
fct.merge(into="main")

# Data Access
df = fct.runs()
node = fct.get("CM_alpha")
result = fct.query("CL > 1.2")
refs = fct.references()
fct.set_reference("Sref", 125.0, units="m2",
    reason="Updated wing area")

# Data Conversion
df = fct.from_pandas(raw_df)   # → TrackedDataFrame
arr = fct.from_numpy(raw_arr)  # → TrackedArray

# Capture & Figures
fct.capture()
fct.save_figure(fig, "cl_polar")

# Preview and Status
fct.preview()
fct.status()
11Workspaces

A Workspace is a personal, server-side context for work before promoting to a shared Branch. Workspaces are implemented as branches with context_type = 'workspace', scoped to the user.

Operations

OperationSDKDescription
Create / Resumefct.workspace()Creates or resumes the user’s workspace
Syncfct.sync()Pushes data to workspace
Promotefct.promote()Selective promotion to a named branch, with optional squash commit
DeleteAPIRemoves workspace and associated data

Workspaces persist across Python sessions. Promotion respects main protection — if main is protected, promotion to main requires a merge. The SDK interface contract is preserved; existing scripts keep working.

fct.workspace()              # create/resume personal workspace
fct.sync()                   # push to workspace
fct.promote(into="experiment")  # promote to branch
12Flow360 Integration

Thread includes server-side Flow360 ingestion (/api/flow360/ routes). The planned SDK integration (fct.ingest.flow360(case_id)) will trigger server-side ingestion and create local tracked references linking the Python session to imported Flow360 data.

13Comments

Every object in Thread is commentable — runs, design conditions, reference quantities, plots, nodes. Comments are threaded, support anchoring to specific items, and include emoji reactions.

The conversation lives with the data. Instead of discussing results in Slack or email, engineers comment directly on the artifact. When someone reviews a branch or approves a merge, the context is right there.

14Search

Thread includes semantic search with full-text indexing across all project data — node names, paths, values, metadata, comments, and commit messages. Useful for large projects where navigating the DAG alone isn’t sufficient.

15Saved Plots

Saved plots are first-class nodes (kind = 'saved_plot') that persist plot definitions — axis mappings, filters, coloring — in the project. They can be scoped to a branch or to the project as a whole.

Every plot point is linked to its source data. Clicking a point on a CL vs. α plot navigates to the simulation that produced it, including the 3D flowfield if available. This extends to derived quantities like Short Period Mode Natural Frequency vs. VEAS.

16Staleness Propagation

When an upstream node changes (e.g. a reference quantity is updated), Thread propagates staleness through the provenance DAG, marking all downstream nodes as stale. This makes it visible which results need recomputation after an input change.

Staleness can be inspected via the API (/api/nodes/.../stale, /api/nodes/.../dependencies) and cleared once results are refreshed.

17Run Table

The Run Table provides a flat, tabular view of all runs in a project. Inputs, outputs, and metadata are pivoted into columns for filtering, sorting, and export. Powered by AG Grid in the frontend. Feature-flagged (run_table).

18Fix Sessions (Provenance Repair)

fct.fix() analyses user scripts for provenance breaks — places where tracked types lose lineage through untracked third-party code — and rewrites the source to repair them. Fix sessions are persisted server-side for review and undo (fct.unfix()).

19Changelog

The Changelog is an activity timeline for the project — every sync, commit, merge, approval, reference change, and comment is recorded as a change_event. Provides a single chronological audit trail across all project activity.

20Invariants
1. Provenance is non-optional for outputs. Every result must link to at least one input and a solver identification.
2. History is never lost. Every mutation is captured in nodes_history.
3. Protected Main accepts data only through Merge.
4. Branch creation is O(1). Copy-on-write, no data duplication.
5. Every Commit has an author and message.
6. Merge Approvals block merges until resolved.
7. Sync is idempotent. Deterministic UUIDs prevent duplicates.
8. Tracked types propagate provenance transparently.
9. Provenance recovery is always available via @track, attach(), scalar(), recover(), and fix().
10. Local and remote state are separable. The SDK works offline.
11. Every object is commentable. Conversations live with the data.
12. Staleness propagates. When an input changes, downstream nodes are marked stale.
21Glossary
TermDefinition
ProjectTop-level container. One aircraft, one campaign.
BranchNamed, versioned namespace for data.
MainSingle source of truth. Optionally protected.
WorkspacePersonal, server-side work context with selective promotion.
NodeAtomic data unit — parameter, result, figure, etc.
EdgeDirected provenance relationship.
CommitNamed savepoint with author and message.
SyncLocal-to-server data transfer.
MergeBranch-to-branch data movement with optional approvals.
Tracked Typenumpy/pandas subclass recording provenance.
auto_setup()Zero-config monkey-patching.
@trackProvenance re-attachment decorator.
scalar()Named DAG node for scalars.
fix()Source-code rewriter for provenance breaks.
@cachedContent-addressed caching.
ConfigurationNamed vehicle variant within a Project.
Design ConditionReference quantity scoped to a Configuration.
Merge ApprovalReview gate before merge proceeds.
Copy-on-WriteIncremental divergence on branch.
ltreePostgreSQL hierarchical path type.
nodes_historyTrigger-populated audit table.
CommentThreaded annotation on any object.
Saved PlotPersisted plot definition with axis mappings.
StalenessDownstream invalidation when inputs change.
ChangelogChronological activity timeline.
Run TableFlat tabular view of all runs.
Fix SessionProvenance break detection and repair.
MultiFidelityModelBlends results across solver fidelities.
AerodynamicDatabaseStructured ADB with parameter space and gap detection.
query()Filtered data retrieval from project.
capture()Figure capture with provenance embedding.