fTimer Architecture Reference
June 9, 2026 · View on GitHub
When to read this: For current-state architecture, repository layout, validation, and maintainer workflow context. This document describes what ships on current
main, not a future target state.
fTimer Architecture Reference
This document is the current-state architecture reference for fTimer.
Use it to understand how the repository is organized today, how the major modules fit together, what validation paths are real, and how the documented maintainer workflow ties into the codebase. For the exact runtime contract, prefer docs/semantics.md. For the user-facing quick-start and build/install guidance, prefer README.md. For the historical phase roadmap that led to the current implementation, use docs/implementation-history.md.
When current-state sources disagree, use this repository-wide precedence order: current code under src/, then current behavioral tests, then docs/semantics.md, then README.md, then docs/design.md.
Current Scope
Current main ships a small, correctness-first wall-clock timing library for modern Fortran. The strongest supported stories today are disciplined serial timing and pure-MPI timing. OpenMP support is split between the existing master-thread-only compatibility carve-out for ftimer/ftimer_core and the explicit ftimer_openmp_t serial-lane and level-1 worker timing runtime.
Implemented capabilities include:
- stack-based start/stop timing with context-sensitive accounting
- configurable mismatch handling (
strict,warn,repair) withstrictas the default - structured local summaries plus formatted local report output and CSV export
- procedural wrappers over an OOP core
- MPI-reduced global summary fields on every participating rank after a descriptor-hash preflight
- sparse MPI union summaries plus explicit sparse text and CSV reports
- limited OpenMP master-thread-only timer guards for
ftimer/ftimer_core - explicit
ftimer_openmp_tserial-lane and level-1 worker timed-region / id-first thread-lane timing - stopped-run local OpenMP summaries, text reports, and CSV output through
ftimer_openmp_t - strict stopped-run MPI+OpenMP rank/lane summaries, text reports, and CSV
output through
ftimer_openmp_t - sparse union MPI+OpenMP participation summaries, text reports, and CSV output
through
ftimer_openmp_t - installable CMake package exports, smoke tests, pFUnit behavioral tests, and a benchmark harness
fTimer does not currently provide built-in hardware counter backends, JSON export utilities, a serious profiler-backend callback contract, or general thread-safe access to the existing ftimer/ftimer_core APIs from OpenMP worker threads.
It also does not provide accelerator/device synchronization hooks or implicit MPI
barriers; callers own those synchronization decisions when interpreting
wall-clock intervals.
Repository Map
The repository layout that matters for day-to-day work is:
fTimer/
├── src/
│ ├── ftimer_types.F90
│ ├── ftimer_csv_validation.F90
│ ├── ftimer_clock.F90
│ ├── ftimer_core.F90
│ ├── ftimer_summary.F90
│ ├── ftimer_mpi.F90
│ ├── ftimer_core_summary_bindings.F90
│ ├── ftimer_openmp.F90
│ └── ftimer.F90
├── tests/
│ ├── test_phase0_smoke.F90
│ ├── test_openmp_api_smoke.F90
│ ├── test_openmp_api_diagnostics.F90
│ ├── test_*.pf
│ ├── mpi/
│ └── check_*_contracts.cmake
├── examples/
│ ├── basic_usage.F90
│ ├── nested_timers.F90
│ ├── mpi_example.F90
│ ├── openmp_example.F90
│ ├── openmp_worker_example.F90
│ └── mpi_openmp_example.F90
├── bench/
│ └── ftimer_bench.F90
├── docs/
│ ├── semantics.md
│ ├── design.md
│ ├── implementation-history.md
│ └── workflows/
└── .github/
├── workflows/
└── prompts/
Two supporting points matter here:
docs/design.mdis now the current architecture reference.docs/implementation-history.mdholds the historical phase roadmap so this document can stay focused on the current repository.
Module Architecture
The shipped module layering is:
ftimer.F90
└─ procedural wrappers over the default global instance
ftimer_core.F90
└─ ftimer_t state and timer lifecycle entry points
└─ summary/report bindings implemented in ftimer_core_summary_bindings.F90
ftimer_summary.F90
└─ local structured summary building plus local/MPI text formatting
ftimer_mpi.F90
└─ MPI descriptor preflight and reduced summary fields
ftimer_clock.F90
└─ default wall clock, MPI wall clock wrapper, date-string helper
ftimer_csv_validation.F90
└─ shared CSV append-target validation helper
ftimer_openmp.F90
└─ explicit opt-in OpenMP lifecycle/catalog/timed-region thread-lane runtime
ftimer_types.F90
└─ kinds, constants, summary/container types, and callback interfaces
The CMake source order reflects the real dependency order:
ftimer_types.F90ftimer_csv_validation.F90ftimer_clock.F90ftimer_core.F90ftimer_summary.F90ftimer_mpi.F90ftimer_core_summary_bindings.F90ftimer_openmp.F90ftimer.F90
Module Roles
ftimer_types.F90 is the shared foundation. It defines kind parameters, error codes, mismatch-mode constants, MPI summary-state constants, summary types, call-stack/context helpers, and the abstract interfaces for clocks and lightweight callback hooks.
ftimer_clock.F90 is an internal time-acquisition helper module. Serial builds use system_clock; MPI-enabled builds can use the MPI wall clock path. Tests rely on the injectable clock interface so behavior is deterministic without sleeps.
ftimer_csv_validation.F90 is an internal CSV append-target validation helper. Core, MPI, OpenMP, and hybrid CSV output paths pass explicit schema headers, format versions, summary kinds, and record types to keep schema-specific behavior visible while sharing quoted-field, CR, newline, and record-prefix validation.
ftimer_core.F90 owns the mutable timer state in ftimer_t: timer definitions, active stack state, mismatch policy, communicator capture, lightweight callback registration, and the guarded timer entry points.
ftimer_core_summary_bindings.F90 is the submodule-backed binding layer that connects ftimer_t to local summary generation, formatted reporting, CSV export formatting, and file-output entry points without collapsing all summary logic into the core module body.
ftimer_openmp.F90 is the additive, explicit opt-in API surface for true OpenMP
worker timing. Its lifecycle/configuration, timer catalog, timed-region, and
id-first thread-lane timing operations are usable today, along with stopped-run
local OpenMP summary, report, and CSV output plus strict stopped-run MPI+OpenMP
rank/lane summary, report, and CSV output plus sparse union stopped-run
MPI+OpenMP rank/lane summary, report, and CSV output.
ftimer_summary.F90 is an internal summary/report helper module. It turns timer state into structured local summaries and formatted report text. This is where entry ordering, explicit summary-tree linkage (node_id/parent_id), depth attribution, percentages, self-time computation, and strict/sparse MPI text formatting are assembled for reporting.
ftimer_mpi.F90 is an internal MPI summary helper module. It adds cross-rank behavior on top of local summaries, uses communicator-wide preflight collectives to verify that all ranks agree on the timer descriptor set for strict summaries, and then populates reduced MPI fields only where that contract allows. It also owns the sparse/union descriptor builder, which gathers a canonical descriptor union and reduces participation-aware entry statistics without weakening strict mpi_summary().
ftimer.F90 exposes the procedural API by forwarding to the default saved ftimer_t instance. Shared types and constants still come from ftimer_types; they are not re-exported from ftimer.
Runtime Design Highlights
The current implementation is organized around a few design choices that show up across the code, tests, and docs:
- Strict stack-based nesting is the baseline model. Timer overlap is not supported.
- Context-sensitive accounting means the same timer name under different parent stacks is tracked independently.
- Timing data is structured data first and formatted text second.
- Local summary entries keep preorder compatibility for formatting, but they also carry explicit parent-linked tree data within each produced summary object.
- The clock is injectable, which keeps tests deterministic and benchmarking controlled.
- Name-based timing remains the primary ergonomic story, backed internally by mapped resident-timer lookup, mapped per-segment parent-stack lookup, and capacity-based growth so the default path no longer depends on repeated resident-timer linear scans, steady-state context-list scans, or one-slot-at-a-time array growth.
- Per-segment context selection remains fully context-sensitive, but it now uses a per-segment parent-stack index in steady state instead of rescanning the known parent-stack variants for that timer on every hit.
- The explicit
ftimer_openmp_tworker runtime keeps its hot path id-first and private-indexed: catalog names use a serial-context name index, each lane segment uses a parent-stack context index, and each lane records the current timed-region team size once per epoch so warmed workerstart_id/stop_iddoes not enter a shared critical section or query the OpenMP runtime on every call. A timed-region epoch is intended to cover one level-1 OpenMP team shape; callers should close and reopen the fTimer timed region when the OpenMP team shape changes. - Callback hooks are lightweight intra-run hooks for normal start/stop events only; internal mismatch repair transitions must stay invisible to callback consumers, and current
maindoes not define a stronger profiler-backend identity contract. - MPI summary-field reductions are descriptor-validated first, and reduced cross-rank fields are valid only in the documented result shape. The validation itself uses MPI collectives over the init communicator before any timer-data reduction assumes matching canonical entries.
- Sparse/union MPI summaries are a separate opt-in result shape. They build a descriptor union with participation-aware entry statistics while preserving strict-summary descriptor validation for
mpi_summary(). The descriptor-union exchange uses exact per-rank descriptor lengths and packed character payloads instead of padding every rank to the communicator-wide maximum descriptor count and path length; local path materialization, all-rank gathered packed descriptor metadata/payloads before deduplication, MPI default-integer count limits, and final union-sized reduction arrays remain the documented scale boundaries. - MPI timed regions are rank-local wall-clock intervals unless the caller adds
synchronization;
mpi_summary()reduces the recorded intervals but does not imply phase-entry or phase-exit barriers. - MPI-enabled fTimer is used inside the MPI runtime lifetime: after
MPI_Initand beforeMPI_Finalize. The communicator captured byinit(comm=...)is a non-owning handle that the caller must keep valid while fTimer summaries, reports, finalization, or reinitialization may use it. - OpenMP support has two distinct paths: guarded
ftimer/ftimer_coreoperations still run only on the master thread whenFTIMER_USE_OPENMP=ON, whileftimer_openmp_tprovides opt-in id-first timing for serial and level-1 OpenMP worker lanes plus stopped-run local OpenMP summary, report, CSV output, strict MPI+OpenMP hybrid rank/lane reductions, and separate sparse union MPI+OpenMP hybrid rank/lane reductions.
Those runtime semantics are specified in detail in docs/semantics.md; this document focuses on how the repository realizes them.
Public API Shape
The public surface on current main is split between:
- the procedural API in
use ftimer - the OOP API through
type(ftimer_t)fromuse ftimer_core - the explicit opt-in OpenMP API surface in
use ftimer_openmp - shared types and constants from
use ftimer_types
The supported source-level module surface is intentionally limited to ftimer, ftimer_core, ftimer_openmp, and ftimer_types. ftimer_openmp is the additive opt-in API surface for true OpenMP worker timing; its lifecycle/configuration, timer catalog, timed-region, id-first thread-lane timing, local OpenMP summary/report methods, strict MPI+OpenMP hybrid summary/report methods, and sparse union MPI+OpenMP hybrid summary/report methods are available now. Module-level public symbols are checked against tests/public_symbol_allowlist.txt so runtime storage helpers are not accidentally promoted into the stable downstream contract. The installed include tree is a curated compiler module artifact set; it currently includes ftimer_clock.mod, ftimer_csv_validation.mod, ftimer_summary.mod, and ftimer_mpi.mod so downstream builds see a coherent Fortran module set, but those implementation modules are not stable import targets. The installed package also carries share/doc/fTimer/installed-api.md and share/doc/fTimer/LICENSE, and the installed-consumer smoke test checks those documentation artifacts against the source tree.
The currently exported procedural entry points are:
ftimer_initftimer_finalizeftimer_startftimer_stopftimer_scopeftimer_guard_tftimer_start_idftimer_stop_idftimer_lookupftimer_resetftimer_get_summaryftimer_mpi_summaryftimer_mpi_union_summaryftimer_print_summaryftimer_write_summaryftimer_write_summary_csvftimer_print_mpi_summaryftimer_write_mpi_summaryftimer_write_mpi_summary_csvftimer_print_mpi_union_summaryftimer_write_mpi_union_summaryftimer_write_mpi_union_summary_csvftimer_default_instance
The currently supported ftimer_core OOP surface includes:
ftimer_tftimer_oop_guard_tftimer_oop_scope
Important current-state API notes:
ierris now the last optional argument in theinitsignatures. Integerinitoptions such asmismatch_modeandierrmust be passed by keyword. Keywords are recommended for readability on allinitcalls.- In MPI builds, the communicator argument is
type(MPI_Comm)frommpi_f08; legacy integer communicator handles are not accepted. - In MPI builds, fTimer must be used after
MPI_Initand beforeMPI_Finalize; communicator arguments are borrowed, not duplicated or owned. init,reset, andfinalizetreat active timers as an error in both API styles. Withierrthey returnFTIMER_ERR_ACTIVE; withoutierrthey warn and leave state untouched rather than force-stopping or cleaning up implicitly. InFTIMER_USE_OPENMP=ONbuilds, that lifecycle-diagnostic contract applies on the master thread; non-master lifecycle calls remain suppressed no-ops.- Repairing stop mismatches remains an explicit
mismatch_modedecision; omittedierralone is not a recovery mode. - Name-based
start/stopremains the default user path.lookup()plusstart_id()/stop_id()is documented as an optional cached-id hot path rather than a separate primary workflow. ftimer_scope()andftimer_guard_tprovide a small default-instance scoped guard for lexical blocks.ftimer_corealso exposes pointer-based OOP scoped timing throughftimer_oop_guard_tandcall ftimer_oop_scope(timer_pointer, guard, name, ierr). Explicittimer%start()/timer%stop()remains the primary OOP API; the scoped form is for lexical blocks where the timer pointer target visibly outlives the guard.ftimer_coreexposes low-level scoped-activation helpers only so the public scoped guard APIs can implement exact activation ownership without duplicating start/stop internals.ftimer_typesalso exposes runtime storage types that helper modules currently need to share. These names are unstable public-by-necessity internals, not a supported downstream API:ftimer_internal_start_scope_activation,ftimer_internal_stop_scope_activation,ftimer_call_stack_t,ftimer_context_list_t, andftimer_segment_t. Callers should useftimer_scope(),ftimer_oop_scope(), or explicitstart/stop, and should inspect structured summary result types instead of runtime storage.get_summary()is the local structured summary path.ftimer_summary_tentries now retainname/depthand also exposenode_id/parent_idlinks that are stable only within one produced summary object.print_summary()andwrite_summary()format local report text.write_summary_csv()exports local summaries in the versioned CSV record format for non-Fortran tooling.mpi_summary()returns a distinctftimer_mpi_summary_twhose fields are globally meaningful on every participating rank.mpi_union_summary()is the separate opt-in sparse/union MPI API. Its public result model isftimer_mpi_union_summary_t; entry statistics are defined over participating ranks while communicator total-time fields remain all-rank reductions.print_mpi_summary()andwrite_mpi_summary()are the first-class strict communicator-level MPI reporting paths; they still buildftimer_mpi_summary_tand preserve descriptor-inconsistency failures.write_mpi_summary_csv()exports the full reduced strict MPI summary fields as the same versioned CSV record format from communicator root. CSV format version2is the current local/strict machine-readable schema line and signals signed-64-bit localcall_countand MPImin_call_count/max_call_countfields; MPIavg_call_countremains real-valued.print_mpi_union_summary()andwrite_mpi_union_summary()are the explicit sparse/union MPI text reporting paths. They buildftimer_mpi_union_summary_t, report per-entryParticipatingand derivedMissingcounts, and keep participating-rank statistics clearly labeled.- Sparse CSV export is an explicit separate public path through
write_mpi_union_summary_csv()/ftimer_write_mpi_union_summary_csv(). It usessummary_kind=mpi_union, a dedicated participation-aware schema, and participating-rank statistic labels rather than overloading strictsummary_kind=mpirows. set_clock()/clear_clock()andset_callback()/clear_callback()are the supported configuration entry points; direct mutation of raw runtime internals is no longer part of the public contract.on_eventremains a lightweight intra-run hook; the current public surface does not promise stable semantic timer identity for external-profiler integrations.ftimer_typesownsftimer_summary_t,ftimer_mpi_summary_t,ftimer_mpi_union_summary_t,ftimer_metadata_t, and mismatch constants.
Build, Test, and CI Reality
The repository supports three distinct validation layers, and the architecture doc should reflect all three accurately.
Local Build Modes
Supported local build paths today are:
- serial smoke/library build validated with GNU Fortran and LLVM Flang
- serial pFUnit tests with
gfortranplus a matching pFUnit install - MPI builds through GNU Fortran MPI wrapper compilers, with CI smoke/install-consumer coverage for OpenMPI and MPICH and MPI pFUnit coverage for OpenMPI plus MPICH on hosted Ubuntu 22.04
- OpenMP builds with GNU Fortran and LLVM Flang for the master-thread-only carve-out plus the explicit
ftimer_openmp_tworker timing runtime; pFUnit OpenMP guard coverage remains ongfortran - MPI+OpenMP smoke coverage for the current compatibility mode, installed opt-in
ftimer_openmpworker API, strict hybrid rank/lane summary/report/CSV path, and sparse union hybrid participation summary/report/CSV path - benchmark harness builds with
FTIMER_BUILD_BENCH=ON
The top-level CMake options that shape those paths are:
FTIMER_USE_MPIFTIMER_USE_OPENMPFTIMER_BUILD_SMOKE_TESTSFTIMER_BUILD_TESTSFTIMER_BUILD_EXAMPLESFTIMER_BUILD_BENCH
The MPI and OpenMP enablement paths are guarded at configure time:
FTIMER_USE_MPI=ONrequires a compiler/toolchain pair that can compile a minimalmpi_f08probe against the discovered MPI installation.- MPI builds also require the same
mpi_f08path to compile theMPI_Type_match_size/MPI_ERRORS_RETURNvalidation calls used to select reduction datatypes forreal(wp)andinteger(int64). FTIMER_USE_OPENMP=ONis admitted only for validated compiler IDs (GNUandLLVMFlangtoday), requiresOpenMP::OpenMP_Fortranto resolve successfully, and runs a configure-time probe that compiles, links, and executesomp_lib, a two-thread parallel region,omp_get_thread_numintrospection, and!$omp mastersemantics. LLVM Flang OpenMP validation requires CMake 3.24 or newer so CMake reports compiler IDLLVMFlang; cross-compiling or execution-restricted package builds may use the advancedFTIMER_OPENMP_ASSUME_MASTER_PROBE_OKoption only after independently validating equivalent runtime semantics for the selected compiler/runtime pair.
Test Categories
The current test inventory is:
- smoke tests in
tests/test_phase0_smoke.F90andtests/test_openmp_api_smoke.F90, OpenMP diagnostic stderr capture throughtests/test_openmp_api_diagnostics.F90whenFTIMER_USE_OPENMP=ON, runtime execution ofbasic_usage, OpenMP compatibility and worker example execution whenFTIMER_USE_OPENMP=ON, MPI example execution whenFTIMER_USE_MPI=ON, MPI+OpenMP example execution when both feature flags are enabled, installed-package consumer build-and-run checks, and build-contract regression checks undertests/check_*_contracts.cmake - serial pFUnit tests for core behavior, summaries, callbacks, reset behavior, call-stack behavior, and procedural parity
- MPI pFUnit tests under
tests/mpi/, validated in CI with GNU Fortran against OpenMPI and MPICH - OpenMP guard tests enabled when
FTIMER_USE_OPENMP=ON, covering the master-thread-only carve-out plusftimer_openmp_tthread-lane timing smoke coverage - MPI+OpenMP example and installed-consumer smoke coverage for the current exported-package dependency story, including an MPI-initialized OpenMP region, explicit
ftimer_openmp_tworker calls, strict hybrid summaries, and sparse union hybrid summaries
The default repository baseline is still the smoke/build-contract path. The full behavioral suite is enabled explicitly with FTIMER_BUILD_TESTS=ON.
GitHub Actions CI
.github/workflows/ci.yml currently runs these jobs:
build-serialbuild-serial-flangbuild-mpibuild-mpi-mpichbuild-mpi-openmptest-serialtest-mpitest-mpi-mpichbuild-openmpbuild-openmp-flangtest-openmpbuild-contract-regressionsbuild-benchbuild-openmp-benchbuild-mpi-openmp-benchlint
That means pFUnit-backed serial, OpenMPI MPI, MPICH MPI, GNU OpenMP guard,
LLVM Flang OpenMP smoke, and OpenMPI+OpenMP smoke/install-consumer coverage
are part of current CI now; they are not deferred future work. Serial,
OpenMP, and MPI+OpenMP benchmark CSV smoke jobs also build ftimer_bench and
verify parseable CSV output for the configured feature mode.
The issue #255 hosted-runner investigation found that Ubuntu 24.04's apt
MPICH 4.2.0/Hydra launcher can start /usr/bin/mpiexec.mpich -n 2
Fortran MPI programs as two singleton MPI_COMM_WORLD ranks on hosted
runners, which made pFUnit report Insufficient processes to run this test. (PE=0) for [npes=2] cases. The MPICH CI jobs now run on hosted Ubuntu
22.04 and guard the launcher with a raw two-rank MPI probe before claiming
coverage. The MPICH pFUnit job builds pFUnit v4.16.0 with
/usr/bin/mpifort.mpich, verifies the installed package reports
PFUNIT_MPI_FOUND "TRUE", and runs both ftimer_mpi_tests and
ftimer_mpi_tests_4pe through /usr/bin/mpiexec.mpich. The separate
build-mpi-mpich job covers MPICH smoke/install-consumer behavior on the
same runner family after the launcher probe.
The hybrid build-mpi-openmp job configures both FTIMER_USE_MPI=ON and
FTIMER_USE_OPENMP=ON, builds, and runs smoke/install-consumer checks for
today's compatibility mode, the installed opt-in ftimer_openmp worker API,
the MPI+OpenMP example, strict MPI+OpenMP rank/lane summary/report/CSV paths,
and sparse union MPI+OpenMP participation summary/report/CSV paths.
Local Homebrew MPICH 5.0.1 was not a valid reproduction path because it does
not install mpi_f08.mod, so it fails fTimer's configure-time MPI contract
probe. A GitHub-hosted NVHPC 26.3 serial smoke/install-consumer trial installed
and built successfully, but the generated executables aborted at runtime with
DEALLOCATE: memory at (nil) not allocated, so NVHPC validation remains
deferred rather than claimed. The contract-regression job also verifies the
configure-time MPI/OpenMP gates and the documented Makefile wrapper behavior.
Dedicated artifact upload for OpenMP and MPI+OpenMP benchmark CSVs remains
follow-up work under issue #285.
Local issue #277 OpenMP benchmark evidence was collected on June 8, 2026 with
GNU Fortran 15.2.0 and FTIMER_USE_OPENMP=ON. The added rows cover worker
context cardinality, OpenMP catalog registration/lookup, concurrent worker
lanes, split-object lane timing, and lazy lane first touch. The 1000-context
warmed worker row moved from about 961 ns/op to about 150 ns/op, OpenMP catalog
registration at 1000 timers moved from about 1313 ns/op to about 173 ns/op,
catalog lookup at 1000 timers moved from about 1283 ns/op to about 45 ns/op,
and the 8-lane concurrent worker row moved from about 251 ns/op to about
21 ns/op after eliminating the per-call epoch-team critical section and then
the residual per-call team-size query. A direct dense-lane false-sharing
comparison measured the shared 8-lane object row at about 21 ns/op versus about
16 ns/op for one split object per lane in the refreshed local run. That leaves
a small same-order absolute delta rather than the former critical-section-scale
bottleneck, so padding or moving lane records did not earn its complexity for
the supported measured lane count. The configured-capacity lane first-touch rows
(K=3 versus K=65, one participating worker lane, 1000 registered timers)
remained comparable at about 546 ns/op versus about 504 ns/op, so the
implementation kept lazy per-participating-lane segment allocation and did not
add a public reserve/warm API.
Maintainer Workflow
Repository workflow guidance lives in docs/maintainer.md and the workflow-specific docs under docs/workflows/. The standard flow for scoped work on current main is:
- Create or link the GitHub issue first.
- Create a feature branch from updated local
main. - Implement and validate the change.
- Open a pull request to
main. - Let the review router apply automatic labels, then verify the result and add any extra labels the diff still needs.
- Monitor review output and address every finding.
- Do not merge while merge-blocking findings remain unresolved.
The required label policy is current and specific:
- the Codex review router always applies
codex-software-review - the router may also auto-apply methodology, red-team, docs-contract, test-quality, build-portability, API-compat, and MPI-safety labels when the diff matches the rules in
.github/codex-review-roles.json - maintainers may still add optional deeper-review labels such as performance-overhead, pragmatic-design, adoptability, or completion-audit when the diff warrants them
The repository also carries a detailed prompt library under .github/prompts/detailed/ for fallback reviews and selective deeper review roles. The machine-readable review-routing catalog lives in .github/codex-review-roles.json.
Documentation Boundaries
The docs set is intentionally split by audience and purpose. The README is the normal entry point for users; maintainer and coding-agent workflow files are kept available for repository operations without being part of the first-use library path.
User docs
README.md: user-facing setup, usage, limitations, and examplesdocs/troubleshooting.md: symptom-oriented remedies for first-use build, MPI, OpenMP, CSV, and summary/report failuresdocs/semantics.md: current runtime contract and behaviordocs/installed-api.md: installed package, public symbol, and downstream consumption contractdocs/csv-schema.md: CSV schema families and reader-aid fixturesdocs/openmp-timing-modes.md: OpenMP and MPI+OpenMP mode selection, accepted current examples, and migration guidance
Maintainer and release docs
CONTRIBUTING.md: contribution expectations and contributor-facing validationdocs/design.md: current architecture, repository layout, validation reality, and workflow contextdocs/maintainer.mdanddocs/workflows/: issue/PR/review operating proceduresdocs/release.md: release checklist, validation matrix, and artifact policydocs/release-evidence.md: support-claim evidence and caveats
Coding-agent docs
AGENTS.mdandCLAUDE.md: coding-agent repository instructions, build/test context, and source-of-truth rules.github/prompts/: Codex review prompt contracts and fallback prompt library
Historical docs
docs/history/: historical decision records and implementation-planning artifacts. These are not the navigation surface for current behavior.docs/implementation-history.md: historical phase roadmap and landing history
Keeping those boundaries sharp matters. When current behavior changes, update the document that owns that contract instead of leaving design notes or historical plans to imply current behavior indirectly.
Deferred Work
Future-facing ideas should stay clearly separated from the current architecture reference. Examples that remain intentionally deferred today include:
- built-in hardware counter or power-measurement backends
- richer export formats beyond summary CSV, such as JSON or trace/event formats
- broader OpenMP support beyond the landed
ftimer_openmp_tserial-lane / level-1 worker runtime. Remaining deferred areas include nested/team support, OpenMP task migration, broader thread-safe behavior for the existingftimer/ftimer_coreAPIs, and production black-box accounting coverage around the public OpenMP summary/result surface. User-facing mode selection and migration guidance live indocs/openmp-timing-modes.md. - stable semantic callback identity or a stronger external-profiler integration contract
- explicit reservation/preallocation APIs for known timer sets, if profiling shows the new internal capacity strategy is still not enough for an adopter workload
If deferred work needs a maintained roadmap, record it in docs/implementation-history.md or in the relevant issue or PR discussion rather than mixing it into the current-state architecture narrative above.