Software Requirements Specification¶
The SRS of pyflightstream: the authoritative public reference for what the package must do, must not do, how it must behave, and how the requirements trace to evidence. It follows the reference SRS template (shared with the reference ITACA library), adapted to this documentation site.
Document identity¶
| Field | Value |
|---|---|
| Document | pyflightstream Software Requirements Specification |
| Version | 1.43.0 |
| Status | Living document |
| Author | Geovana Neves |
| First published | 2026-07-22 |
| Supersedes | The private founding SRS (design record DLV-002, 2026-07-21), sanitized and updated for publication |
This SRS is a living document. Requirements are added, refined, or deprecated as use consolidates; every change increments the document version and lands in the revision history below. Deprecated requirements are never deleted: they keep their identifier forever and are tagged deprecated.
The package is implemented with assistance from large language model tooling. Every implementation derived from these requirements goes through review by the owning seat before acceptance. The SRS describes the desired behavior; the code is verified against the SRS, and the SRS is corrected only when a requirement itself is found wrong or ambiguous.
Chapters¶
- Introduction: purpose, context, and motivation.
- Philosophy: the evidence discipline and the didactic policy that shape every requirement.
- Scope: what is in, and the explicit non-requirements.
- Data and evidence model: the command database, the run manifest, and the workspace.
- Architecture: the layered pipeline and its rules, with the generated architecture overview as the live companion.
- Functional requirements: FR-01 to FR-111, each with origin, status, and evidence.
- Non-functional requirements: NFR-01 to NFR-28.
- Standards alignment: the external practices this project adopts, with references.
- Roadmap: delivered milestones and the open lines.
The requirement set is also published as a machine-readable index at
reports/requirements-index.json, generated from these pages and
checked against them by two Tier 1 tests; which accepted item became
which identifier is recorded in the
acceptance mapping.
Conventions¶
Requirement identifiers are stable and never renumbered:
| Prefix | Meaning |
|---|---|
| FR-XX | Functional requirement (what the package shall do) |
| NFR-XX | Non-functional requirement (how the package shall behave) |
| NREQ-XX | Non-requirement (what the package shall not do or be) |
| BRF-XX | Stakeholder brief item (a confirmed founding decision) |
| PP-X | Pain point verified in the predecessor toolchain |
Each requirement carries an origin tag (the BRF and PP items it answers) and one status:
| Status | Meaning |
|---|---|
| implemented | Corresponding code exists, tested, and shipped |
| pending | Agreed, not yet implemented |
| deferred | Implementation waits on an external gate (usually licensed-machine evidence) |
| draft | Still being refined |
| deprecated | Superseded; kept for traceability |
Statuses cite their evidence: a milestone in the roadmap,
a committed report under reports/, or a plan item. Nothing is marked
implemented without a shipped test behind it.
One clarification, because the 2026-07-27 batch made the distinction visible and a reader met the same badge meaning two things. A requirement whose normative core is shipped and guarded is implemented, and any limit on that core is stated in the requirement's own text rather than hidden by the badge (NFR-24 is the example: its glossary half is guarded by a test and its glossed-at-first-use half is a review check, and it says so). A requirement whose normative core does not bind yet is pending even when the mechanism it will use is already shipped (NFR-20 is the example: the deprecation ledger and its deadline guard exist, and the policy itself starts at 1.0).
Revision history¶
| Version | Date | Change |
|---|---|---|
| 1.43.0 | 2026-09-14 | FR-100 is added: a row states TRANSLATE as a list of records with the grammar of ROTATE, DISTANCE in metres along one axis of a named frame and one declared ALIAS; the surfaces move in that frame with their vertices split from their neighbours, every owned and auxiliary frame moves to its new absolute origin once, the kept hub is shared with a rotation, and every translation precedes every rotation. FR-71's doubling is reached by a rendered script: the kept hub frame now reaches the post-processing, where only the unit tests had reached it. FR-35 and FR-71 are amended by FR-100 |
| 1.42.0 | 2026-09-14 | FR-99 is amended twice: each submitted point runs in its own datapoint folder, with its action files, clock and descriptor, and the collect stage files its outputs in place; and FR-96 opens the archived saved simulation by absolute path and runs a RESTART row under the campaign that recorded the stop; FR-80 imports a cited survey by absolute path and refuses a name inputs/profiles/ does not hold. FR-99 also gains the HPC profile's [builds] table: a row keeps naming one build and the profile states what its scheduler calls that build, through {fs_build_alias}, refusing an unmapped build before any point is submitted; the sentence that the descriptor already states the build a submitted job runs on is corrected, because the table declares the build and does not verify it. FR-35 gains the workspace-wide POL rule: every row of every matrix of the workspace, RUN = 0 rows and a matrix planned from outside the root included, is read for a repeated POL and every repeat is named at once, and pyfs-matrix plan --update-ids renumbers the repeated rows of the planned matrix alone |
| 1.41.0 | 2026-09-14 | FR-96 ENTERS AS IMPLEMENTED: a row stating RESTART now continues the march the wall clock stopped, in all three forms, on the measured fact that the solver resumes an unsteady march from a saved file and runs the new iteration count it is given. The step count is a REMAINDER and not a total, because the solver has already marched what it marched; the outputs a continuation replaces are archived into archive/<day and hour>/ under that datapoint's own folder, stamped because a point can be continued more than once; and a continuation's run id is <campaign>/sim_<id>/r<stamp>/<tag>, so the point tag still ENDS the run id. The requirement had carried pending and a body saying the release REFUSED the key, which is the behaviour of the release before this one; that paragraph is kept in the past tense rather than deleted, because a reader on an older release meets it and should find it described. FR-99 is amended: the collect stage's claim that it ASSESSES a collected point is now true of the code, which it was not when the requirement was written. Two further names are reserved to the package and refused in a row, RESTART_FROM and RESTART_ITERATIONS, because a row stating them reached the builder with the continuation facts already present and skipped the resolution that checks a recorded run exists, that it stopped in a continuable state, and that its outputs are archived before they are replaced |
| 1.40.0 | 2026-09-11 | FR-92 ENTERS AS IMPLEMENTED: each datapoint collects its outputs into sims/<sim>/datapoints/DP-<point>/, one folder per point, steady or unsteady, named by the point tag that already ends the run_id and names the generated script. A swept row could not be judged past its first point: the points shared one outputs/, so the standard assessor found two files that both read as loads tables and refused, and the remedy it offered was the one its own text ruled out for a swept case. The fix is the LAYOUT and not the selection, because a folder holding several points' evidence cannot say which file is whose and every consumer downstream then re-derives it. FR-84 is SUPERSEDED WITHIN THE SAME RELEASE and amended in place, and FR-33e is amended with it: the destination folder is the point's own, and two POINTS sharing a collected name are still refused at plan time for the PRODUCTS they would collide in, which is where the collision moved when the folders stopped colliding. That refusal was dropped in a first version of the change and restored at the release boundary on a measurement: two points, one declared name, produced one probes table naming both runs while holding one point's data. outputs/ and raw/ are read where a workspace holds them and neither is created |
| 1.39.0 | 2026-09-10 | FR-73 registered, a run chooses whether a family the mesh does not carry is a skip or a refusal; FR-64 and FR-71 to implemented, with FR-64 rewritten to the owning seat's two decisions of that night (required on a MOTIONS list, rotor_speed keeping its name) and FR-71 gaining the rule that a rotated hub frame is written in both frames; FR-59 amended by FR-73 |
| 1.38.0 | 2026-09-10 | THE FR-65 ROUND'S FINDINGS, none of which moved a requirement's state and two of which changed what the code does on the reference rows. The rotors an entry reaches are matched by INTERSECTION with each rotor's families rather than by subset of one of them, so the reference families = ["lifters", "PUSHER"] reaches all three rotors where it reached the pusher alone and did not refuse, because one token matched; a rotor's NAME is read as an alias for its own families on both the expanding and the common-frame path, which is FR-65's own sentence about a rotor name being its own union, given to the reader that did not have it. An entry citing PART of a rotor now emits that part rather than the block's union under the name the user wrote. A partial skip warns naming the frames dropped, where the warning used to fire only when every emission was unplaced, which is exactly the row FR-65's paragraph is about. FR-61 gains the sentence the code stands on: a sector row's copy count is the wheel's blade families divided by the ones THE GEOMETRY CARRIES, so the divisor is read from the file the row opens and the count stays the mesh's, which is FR-61's own line; reading the reference alone answered four for a half sector that stands for two. Ten expansion cases and five sector cases were written, and the two mutants a QA lens installed at the two central lines, which had survived a green suite, now fail two and four cases |
| 1.37.0 | 2026-09-10 | TWO MORE OF THE FOURTEEN MOVE TO IMPLEMENTED, and with them the reference use case plans end to end: FR-65 the frame that decides how a post-processing entry expands, and FR-70 the flight condition's advance ratio governing the motions that state none. Two others changed and neither moved, which is why this row counts two: FR-71 the rotation citing an alias stays PENDING on the SMRP_ORIGINAL half, which is a seat decision, and FR-69's own TEXT was corrected twice while its state was already implemented at 1.36.0. FR-65 gains the line its implementation forced and its own text only half stated: an entry whose rotors the row DOES declare but whose frames THIS RUN did not place is LEFT OUT, as an entry whose families the geometry lacks is, while one reaching no rotor of the row at all is REFUSED, because that one cannot come right on another row. Measured on the reference workspace, that distinction is 19 of the 39 points (pyfs-matrix plan pfs0150/matriz_transicao.fs --dry-run and the same over matriz_work.fs, counting the points whose entries cite a rotor frame the row does not place). FR-70's missing half is named in its own text: a swept key is deliberately kept out of the row's variables, so a row writing ADVANCE_RATIO: sweep had no ratio among them and the condition's ratio reached no motion, blocking 9 of 16 points on "states no rotor speed" (pyfs-matrix plan pfs0150/matriz_transicao.fs --dry-run, before and after the two lines of _motion_view) |
| 1.36.0 | 2026-09-10 | FR-69 IS IMPLEMENTED: SWEEP_TYPE left the layout, the verified matrix is 13 columns, and the swept variable is the key of FLIGHT_CONDITION carrying the word sweep. Two statements of the cost are corrected because they were ESTIMATES and the migration was then measured. FR-69 said eleven rows of the licensed matrices use the paired AL/BE code and each becomes one row per sideslip; counting them, a paired code whose second axis holds ONE value is one swept variable written in two columns and folds with the same rows, so exactly ONE row in the whole repository varies both angles and 9 of the 10 live matrices convert with no hand edit. FR-10's fourth-break paragraph said the upgrade of such a file changes its ROW COUNT; it does not, because the converter REFUSES that row instead, naming it, since each new row needs a POL of its own and a POL is run identity. FR-69 also gains the promise the migration turned on: THE UPGRADE DOES NOT RENAME A RUN, so an angle the row holds is carried at every point and the tags that end every run_id in every existing manifest survive the conversion |
| 1.35.0 | 2026-09-10 | SEVEN OF THE FOURTEEN MOVE TO IMPLEMENTED, each carrying the test that fails when it is violated and the commit that built it: FR-59 the reference's vocabulary, FR-60 the rotor block, FR-61 the row that names its rotor by alias, FR-62 the frames that take the alias as their radical, FR-63 the ratio resolved against each rotor's own diameter, FR-66 the symmetry-loads flag on the row, FR-72 the custom frame in the reference. FR-64 and FR-69 stay pending on the half each still owes, which their own text names: the clock warns only on a row of several motions, and the rotor_speed_ref rename was not made; the sweep's column removal is built and mid-migration on a branch. FR-60's paragraph on the alias field is corrected to OPTIONAL, which is what shipped after an interface review found the refusal telling a user to drop a field the model required |
| 1.34.0 | 2026-09-10 | THE ROTOR VOCABULARY THE AUTHOR DESIGNED ENTERS AS FOURTEEN REQUIREMENTS, FR-59 to FR-72, all pending with their evidence owed. They are the design of 2026-09-10, written out first as a use case workspace and read three times before a line of it was built, and they share one shape: a study's vocabulary lives in the reference, a row states which of it moves and at what operating point, and the mesh says what was actually meshed. FR-57 is SUPERSEDED in its own text, because the half of it that shipped is the nesting and the other half moves the rotor's axis, origin, sign and boundaries out of the row and into the reference. Three implemented requirements are amended in the same change rather than left to contradict the new set: FR-10 gains a fourth layout break, the removal of SWEEP_TYPE, and says that the conversion of a paired AL/BE sweep changes a file's ROW COUNT; FR-30c records that the [aliases] table moves to the reference and that whether an alias no member of which resolves is still refused is a seat decision open question; FR-52 records that a pproc entry's frame is the reference's and that the frame decides the expansion. FR-52's own status is unchanged |
| 1.33.0 | 2026-09-09 | FR-40'S QUANTIFIER IS "EVERY COMMAND-LINE OPTION", on the decision of design/68 section PFS-2022.06 (PFS-2022.06.01). "Every user-facing option or parameter" named a set nothing could enumerate; a console script's options can be, and a tier-1 test now builds every parser named in pyproject.toml and holds each option to the rule: it reads its default from a registry key (measured by moving the key) or carries the reason it is not a machine knob. Six flags of pyfs-qa resolve; every other flag of the five scripts is recorded with its reason, and a new flag must choose in the commit that adds it. The requirement stays pending on its Python-API half, which the statement now names as the open part |
| 1.32.0 | 2026-09-09 | NFR-05 STATES HOW ITS FLOOR MOVES rather than a chosen number (PFS-2024.07). The Python and core-dependency window follows SPEC 0, the scientific-python community schedule, computed on a date pyproject.toml states: on 2026-09-09 the floor is Python 3.12, numpy 2.2 and pandas 2.3, where it had been >=3.11 since the first release with no floor on the numerical dependencies. The CI matrices, the ruff target and the classifiers follow the same line, and a tier-1 test re-derives the floors from the release dates and the stated date so the schedule cannot overtake the declaration unnoticed. The decision to adopt SPEC 0 was taken in the session's seat under the delegation recorded for 2026-09-08. NFR-21's clause that a supported version leaves the range only after a release announcing the removal is noted as NOT met by this move, which announces and removes 3.11 in one release; NFR-21 is pending and the changelog carries the announcement |
| 1.31.0 | 2026-09-04 | FR-58 MOVES TO IMPLEMENTED, the same day it entered, because its evidence arrived in the review round that followed it rather than in a later release. The statement gains two things that round produced: the table's pin names match case-insensitively, since the page teaching the FLIGHT_CONDITION cell already promises that of the same three internally capitalised spellings and a file may not teach a second rule; and the claim that the resolved state is the same either way is now held to a workspace built twice and rendered BYTE FOR BYTE, where before it was a session measurement with nothing committed that could re-take it. The two full-precision atmosphere figures the measured paragraph quotes are re-measured by a test for the same reason |
| 1.30.0 | 2026-09-04 | FR-58 ENTERS, on the instruction that the fluid constants need not be typed on every row: a setup artifact may carry them and a row states what varies. It is a widening of FR-54 rather than a change to it, and the two exclusions are the substance. A velocity key and a Reynolds number are refused in that table, because they are what a point IS and a preset several rows share cannot state them; an altitude and an ISA deviation are refused, because they locate a point in the atmosphere the pins exist to replace. Measured 2026-09-04: the three reproduction rows each repeat the same four constants and the reference thirteen-point polar would repeat them thirteen times, while the package's own sea-level atmosphere gives a viscosity and a sonic velocity that differ from the reference tooling's in the fifth digit, so the pins cannot be dropped in favour of the standard atmosphere. Carried by PFS-2030.08 |
| 1.29.0 | 2026-09-02 | THE 0.11.0 REQUIREMENTS ENTER, nine of them pending, derived on the instruction from two sources read side by side: the reference driver, which ran a matrix with no mandatory input, exported eight kinds of file per point and wrote the reference plot-format products afterwards, and the 0.10.1 tree pre-flighted on the reference rows with zero solver time and diffed against the scripts that produced the recorded results. FR-50 says a matrix runs with nothing mandatory on the command line, and records that the version half is a defect against a recorded design rather than scope. FR-51 says a run leaves the study's export set named for the point in the standard convention; measured, the 0.10.1 builders emit two of those eight kinds. FR-52 puts the whole post-processing definition in the pproc artifact, the renamed groups artifact, on the design decision of the same day, and makes the stage part of the campaign; measured, the ENTRY column resolved an artifact no builder consumed and nothing on the run path reached the post package. FR-53 is the reproduction of the reference campaign, one point per run type on build 26.120 with five authorised solver executions, and it is the exit condition of GOAL-011. FR-54 lists the solver settings the reference scripts state that the package did not, with the six-fold symmetry-loads discrepancy already measured on the 0.10.1 reproduction workspace. FR-55 reverses the bare-stem geometry rule and gives the geometry its own inventory, amending FR-33a and the acceptance of PFS-2009.01 in the same change. FR-56 strips the reference artifact of the four inert rotor fields and the second propeller length. FR-57 lets a row state more than one rotor. FR-29a makes the staged geometry a link. NFR-28 says a shipped workspace reads as a set-up and not as a diary. FR-21 gains its reference, the reference products; FR-30c gains the amendment that an undeclared inventory says why. Every new box names the planning nodes that carry it, and each of those nodes names the box, so the trace runs both ways and a checker reads it |
| 1.28.0 | 2026-08-19 | THREE REQUIREMENT STATEMENTS MOVE, one of them off pending, all three on the ruling of the same day and all three written up as proposals first. NFR-15 NAMES ITS ALGORITHM. It said the hashes are computed "with a named algorithm over a canonical serialization" and named neither, which is why it was pending: nothing stopped a volatile field entering one. It now states the rule per KIND, a file digest over the file's raw bytes and a text digest over the UTF-8 encoding, with the exclusions enumerated, and it moves to implemented because the rule is DATA in pyflightstream._digest rather than prose about it, so a module hashing without declaring its canonical form is a tier-1 failure. Nothing hashed changed and no committed manifest is invalidated. FR-33c STOPS DESCRIBING LESS THAN THE CODE REFUSES. It covered one collision refusal while the package makes three of one class, and it now states all three AND states that the SIGNAL differs per shape, because a file write can ask whether the destination exists, a command that asks the SOLVER to write cannot, and a log that appends by design is identified by the pair it forms with the state beside it. FR-10's EVIDENCE LINE follows the sixteenth matrix column: it named the fifteen-column layout, which the reader now recognises and refuses. RECORDED AS WITHDRAWN RATHER THAN OMITTED, because the question is still open: a wider FR-11 was written the same day and taken out again within it. It said the POL column identifies the sims a row GENERATES, against a rotation sweep turning one row into one sim per blade position; a review pass measured the tree and found the package writes one sim per row, a sweep's values becoming points inside it, and the term the sentence introduced defined nowhere else. The one-to-one form stands, and the question returns if the matrix half of PFS-2025.14 lands. ALSO THIS DAY and recorded here because a revision row naming only requirement text hides what the same session settled: the standards page gained an Enforced by column on all fourteen adopted rows, machine-checked and resolved by label rather than by position |
| 1.27.0 | 2026-08-18 | TWO REQUIREMENT TEXTS MOVE, both on the ruling of the same day, and both were proposals this repository had written up and refused to apply on its own authority. FR-02c STOPS ENUMERATING the builds that share a vendor name. The list had gone stale twice by construction, once per registration, and the identical enumeration had already been removed from six other committed homes on 2026-08-17 for exactly that reason, which left the requirement and the README as the last two copies, the README's going in the same session; the refusal message enumerates from the registry and the generated build page carries the tally, so no reader loses the fact. What the requirement states instead is the part that is genuinely a requirement rather than a fact about today's registry: two families exist for two different reasons, one release with its hotfixes sharing a name and two separate releases that happen to share one. NREQ-05 STOPS PROMISING WHAT A DATED MEASUREMENT SHOWED. Its heading and first sentence said the non-requirement excluded NOTHING, which was true of the eight editions swept on 2026-08-08 and stopped being true nine days later when SRC-751 was registered documenting SET_OUTLET_TRAILING_EDGES, a rename made in place that the database does not carry. The corrected wording separates an EXCLUSION from a DEBT: no family is excluded by decision, and a newly registered edition may document a command not yet entered, which is a dated debt in the evidence queue and never an exclusion. Neither change alters any behaviour and both are text; the reasoning behind each is kept beside the requirement rather than only here, because a reader meets the requirement first. RECORDED HERE AND NOT A REQUIREMENT CHANGE, because a revision row naming only requirement text hides what the same ruling settled: the undated compat report of 2026-08-17 stays as it is rather than being re-emitted under a new label, its erratum and the report-level erratum contract both stand, and the two Tier 3 CDo warns on 26.123 gain a committed triage that leaves the references untouched (reports/physics/TRI-26123-CDo_2026-08-18.md) |
| 1.26.0 | 2026-08-17 | FlightStream 26.123 is registered, and it is the first build this project registers as INHERITING NOTHING. FR-02c's candidate list gains it, so the vendor name 26.12 names four registered builds where it named three; the requirement is unchanged and only the enumeration inside it moved, which is recorded here for the same reason 1.23.0 recorded the previous move. WHAT IS NEW IS THE INHERITANCE, and it is a fact about evidence rather than about the build: the two hotfixes before it descend from 26.120, so a command 26.120 records answers for them until a probe on the hotfix overrides it, and that default is right for a hotfix that did not touch the command. It is switched off here on the instruction, and the reason is a number: with descent on, a build issued the day before would have answered for the 363 commands 26.120 can emit with no page of its own manual read and no line run, and the compatibility matrix would have printed a full column on the strength of it. The consequence reaches a caller directly and is stated where they meet it: until a row exists for a command on this build, the emitter refuses it exactly as it refuses a command the build never had, and the enumeration of what that covers is committed and compared by a tier-1 test rather than left as an impression. FR-49's derived level is the rule's first non-hypothetical instance since it was written, and it is recorded as a DATED SEQUENCE rather than as a state, because the state expired inside the session that measured it: registered at registration, since no command carried evidence and nothing could be built; documented once 369 rows were carried forward from the reading of its own edition; operational once a probe run measured 85 of them on the build. All three on 2026-08-17. That is the derivation working rather than an example going stale, and the 1.25.0 row below records the same lesson learned the other way. THE OTHER WORK OF THAT DAY, recorded here because a revision row that names only the requirement it touches hides the scale: 369 documented rows were written by a new pyfs-manual register subcommand rather than by hand, 85 statuses were promoted from a committed probe report, and a registered edition now documents one command this database does not carry, which is a first and is written up against NREQ-05 on the scope page. A PROPOSAL WAS RECORDED AND NOT APPLIED HERE: FR-02c's enumeration had gone stale twice by construction, and the same enumeration was removed from six other committed homes in this session because it goes stale on every registration. Whether the requirement should stop enumerating too was a seat decision on requirement text; the owning seat ruled on 2026-08-18 and the 1.27.0 row above records what was applied |
| 1.25.0 | 2026-08-11 | The removed status gains a SECOND way to cite a measured run, because the probe harness gained the outcome it had been waiting on. The data model had said a measured removal cites its run through probe_ref rather than report, and said why: verified and broken must stay checkable against the compat yaml the harness wrote, and the harness had no removed outcome at all, so a build that lacked a command recorded as broken, which is a claim about a command that is present. RPT-026 measured the solver's own refusal wording on 26.122 and the harness now recognises it, so a removal it measures is promoted by pyfs-qa apply-compat and cites the compat yaml like every other promoted status. probe_ref was expected to go away with that and does not: it holds the rows written before the outcome existed. The rule it was ALSO said to hold, an edition that merely stopped printing a command, is not one it serves, and that is recorded here because it was the stated basis for retention: such a row cites pages in its note and no run at all, which is what the model already requires. Both fields are now read wherever a measured removal is shown, and that is load bearing rather than defensive: the refusal message and the compatibility reference each fall back to the ENTRY's citation, which is a page of an edition that DOCUMENTS the command, so reading one field would print that page beside a sentence saying the solver refused the name. FR-49's worked instance expired the day after it was written: 26.122 derived operational on inherited records alone from 2026-08-10 to 2026-08-11, and the first probe run on the build closed that gap, so the row is dated rather than restated and the rule stands for the next registered hotfix. The licensed evidence queue loses that run and gains what it left behind, which is two debts rather than one: of the 291 commands unprobed on the build, 267 have no probe specification and 24 ran without abort or error and have no instrument that can observe their effect. Writing a specification closes the first and nothing about the second. And the promotion rule is stated at the precision the new outcome forces: every status that rests on a RUN is promoted only by a committed report, while the two document-derived removed provenances are hand-written rows carrying a note and a page, which the shorter wording had been reading as a contradiction of invariant 3 |
| 1.24.0 | 2026-08-10 | NFR-25's residual came due, and the correction is recorded on the requirement rather than left in a commit. The residual said the missing-extra paths are verified by construction and by source rather than by uninstalling the extras, "because the suite runs with them installed". The gap was wider than that admits: NO environment carried every extra and nothing said so. Every install line in all three workflows named the same three of the five, so a test importing one of the other two passed on every maintainer machine and failed in CI, which is how an unguarded import pypdf reached the v0.7.0 tag past every reviewer pass of the release (INC-20260810-2140-shared). Two mechanisms close it and both are new evidence for NFR-25. tests/tier1_offline/test_extras_isolation.py derives, from pyproject and the workflow install lines rather than from a written list, which distributions a CI job may lack, and refuses an unguarded import of one across the trees the requirement enumerates, the root conftest, the doctests inside all of them, and the executable fenced blocks of the README and the docs pages; the derivation is the intersection of the install lines, so a richer leg cannot weaken what the leaner ones prove. And a test-all-extras job installs all five, because guarding the import correctly and stopping there had converted a red test into a permanently silent skip: no job installed manual, so the assertion it protects would have executed nowhere, which is not weaker evidence than a red test but none. Two residuals survive, narrowed and stated on the requirement: no job runs with an extra deliberately uninstalled, so the refusal SHAPE is still verified statically; and the scan does not reach an import made through a console script, an entry point, a pytest plugin, or import_module with a computed argument. No requirement text changes |
| 1.23.0 | 2026-08-10 | FR-01's subject is complete AGAIN, and the second time is the one that means what the first was read to mean. The 1.21.0 edition recorded the database as holding every command any registered manual edition documents, and that was true of the four editions registered THEN; three older builds joined the next day carrying editions nobody had read, so the sentence survived a change that falsified half of it. It is now measured across eight registered editions and pyfs-manual sweep reports zero absent, which includes the sixteen commands only the pre-26.100 editions document and the ten the newly registered 26.122 edition is the first to. READ THAT AT THE LEVEL IT IS MEASURED AT, because the first draft of this row did not and neither did the release notes it was written beside: zero absent is a statement about entry NAMES, and an entry that exists while carrying no row for one edition reads as covered by it. Three builds could not emit a command whose entry the sweep counted, and ten readings across four commands remain deliberately withheld where a version row cannot express a layout. FR-01 therefore gains a SECOND measure rather than a stronger sentence: the sweep now reports, per edition, the commands that edition documents and its build cannot emit, and it is that measure and not the first which can support a completeness claim at row level. FR-01 also gains the reach reporting on its re-check, which landed after this row was first written and is recorded here rather than in a row of its own, since it is the same amendment arriving in two commits. No requirement text changes; what changes is that the claim is checkable against every edition rather than against the newest four, and the count moves from 388 to 414. Three amendments come with it. FR-01's evidence rule gains a re-check: a page citation was written once from a reading and nothing looked at it again, which let ten rows cite a 25.000 manual whose pagination had moved five or six pages under them after the conversion of that edition was corrected. Each pointed at a real page of a real manual, so no guard could see it; pyfs-manual citations now re-reads every cited page against the edition it names. The data model's per-version args override becomes a statement of DIFFERENCE rather than a replacement, filling an argument's unstated fields from the base argument of the same name, because a row that must restate every field to change one is a row where a second field changes by accident, which is exactly what happened while the nineteen overrides of this edition were written and what two existing guards caught. And the derived support level of FR-49 gets a caveat this edition is the first to need: 26.122 derives operational on records inherited from its base release with no command probed on it at all, so the level is read with its evidence and the README says so on the row. FR-02c's candidate list gains 26.122, so the vendor name 26.12 names three registered builds where it named two; the requirement is unchanged and only the enumeration inside it moved, which is recorded here because the requirement text did change and this history is where a text change is found |
| 1.22.0 | 2026-08-09 | The v0.6.0 release edition, and the amendment it carries is one word: FR-02a's canonical scheme goes from 26.XXX to YY.XXX, with BRF-19 reworded to match. The major had been written as a literal while 26 was the only one registered, so registering the 25 series makes it the variable the scheme always meant; no identifier was reassigned and the three fractional digits are unchanged. The amendment also states, on the requirement itself, that registering an EARLIER series is admitted by the append-only rule, which forbids DROPPING a version rather than inserting one, and that release order puts the new entries at the front of the ordered list rather than at the end. FR-02c's run-time counterpart reaches the state it asked for: every registered build now carries a vendor build number from a committed report, so the parse-time cross-check has an answer for all seven rather than for four. What that exposed is recorded here because it changes what the requirement's own wording can promise: the release name a solver PRINTS is not the release name the vendor ships it under, and for 26.120 and 26.121 it is not, both binaries printing 26.1 under the sold name 26.12. The registry records the printed name as its own field rather than deriving it from the alias, since a page that offered a reader the sold name to match on would send the owner of either build to the wrong row |
| 1.21.0 | 2026-08-09 | The v0.5.0 release edition. FR-01's subject is complete: every command that any registered FlightStream manual edition documents is in the database, 388 entries, and every entry carries a version row for each edition that documents it. The second half of that sentence is the one worth reading, because it was measured LAST and it was the larger gap: the coverage sweep answered which commands have no ENTRY and said nothing about entries missing an EDITION, of which there were 122. Forty were on the February build, which is why that build sat at verified while the other three were operational; with those rows written all four derive operational, and FR-49's highest level is now claimed for every registered version. Reading each of the 122 pairs on its page rather than backfilling by rule found four that DIFFER, each now carrying its own per-version grammar, and one of the four is the sharpest evidence for the rule: NEW_SURFACE_SECTION_DISTRIBUTION carries an optional keyword that reached this database from a PROBE of a working 26.120 script and that the two older editions do not document at all. NREQ-05 stays at the empty set it reached in 1.20.0. The probe layer also gained an instrument the SRS should record, since it changes what verified can mean: the saved simulation file is sectioned TEXT rather than the binary the compat reports assumed, so forty commands whose effect nothing could observe became observable, and eighteen are verified through it. Three corrections carried by the release review. FR-39's residual goes from 24 to 20 and the requirement now states an arithmetic it had been quiet about: the ratchet held 29 rather than the published 24, having grown by five sites this cycle wrote and exempted, and it also records that a line-keyed exemption can come to name a different raise after an insertion, which happened here and was caught only by the neighbours failing around it. The data-model page stops describing the argument-citation fallback that v0.5.0 deleted, so cites is documented as the one mechanism it now is, and gains on_command_line. And removed stops being one word for three different claims: an edition stating a withdrawal, an edition going quiet, and a probe measuring a refusal are now distinguished in the row, the last citing its run through a probe_ref admissible for removed alone, since the probe harness has no removed outcome to promote from |
| 1.20.0 | 2026-08-08 | NREQ-05 is NARROWED TO NOTHING, which retires a scope decision without retiring its identifier. It excluded the mesh-wrapper family, the last one it still named, and that chapter entered the database the same day under the design decision: eleven commands read from all four registered editions in one pass. The heading now stands over an empty set, and the two narrowings are kept together because they are the record of a scope decision reversing itself rather than two unrelated edits. The reversal is worth reading whole. Excluding a family nobody had asked for was a reasonable bet about where reading effort was worth spending, and it was wrong in a way invisible from outside the package: a caller meets a refusal for a command their own manual documents and has no way to tell that it was excluded rather than missing. Entering families whole is also what surfaced two defect classes, the parameter-table-versus-sample disagreement and the copied sample, neither of which reading one command at a time would have shown. The wrapper chapter cost the emitter one new capability as well, a keyword block whose leading argument sits on the command's own line, which is the kind of gap an excluded family hides: the shape existed in the manual for as long as the exclusion did, and nothing in the package knew it |
| 1.19.0 | 2026-08-08 | The data model gains two normative sections, both recording rules that were being followed without being written down. An argument specification may declare the entity it cites, the value selecting every entity of that kind, and the exact length of a fixed payload; each of the three exists because the emitter had been deciding a per-command fact by a per-family rule or by guessing from the argument's name, and each was added after that guess was measured wrong. The all-entities value is the sharp case: it defaulted to -1 for every mesh boundary, so six surface commands whose pages state no such form accepted it anyway and the refusal text offered it, which took four review rounds to reach because the first three moved the rule without asking whether the default was itself an unsourced claim. And a chapter now enters for every registered edition that carries it in one pass, rather than from the newest manual alone, because the February 2026 edition is the one that renames things and a chapter entered forward records a grammar the older builds refuse. The residual that rule exists to drain is counted in the CHANGELOG rather than here, a number designed to reach zero being the worst candidate for restating in a living document |
| 1.18.0 | 2026-08-06 | FR-01 is RESTATED and NREQ-05 is NARROWED, both because the command database stopped being a manual-only record. An entry may now rest on a committed probe report where no manual edition documents the command, which exists because RPT-018 measured the solver accepting an erase whose documented spelling it rejects: the working name could not be recorded at all, and callers were pushed to the one emission path with no validation. FR-01 therefore asks for exactly one evidence citation per entry rather than a manual page, the data model gains probe_ref with the two fields mutually exclusive, and documented gains its second admissible evidence. NREQ-05 excluded the CAD, CCS and mesh-wrapper families and said individual commands would enter only when a workflow needed one; the CAD and CAD Create chapters then entered wholesale, 33 commands read from all four registered editions, under the design decision of 2026-08-06 that everything the manuals document enters chapter by chapter. The identifier is kept and narrowed to the mesh-wrapper family rather than retired, and the reason is recorded on the non-requirement itself. Sentences promising a manual page on every entry were corrected in three passes across README, this document, the user guide, CONTRIBUTING, the generated reference, the package docstring and the owning module, and a tier-1 guard now holds the class. Nine of them are pinned verbatim, each verified against the commit that held it, and the guard's own surface list is checked against the tracked prose rather than hand-kept, because a missed SURFACE is what let the class recur twice |
| 1.17.0 | 2026-08-06 | FR-02a and FR-02c are RESTATED after the version registry stopped deriving one fact from the identifier. FR-02a described the last canonical digit as indexing "intermediate hotfix builds (0 = the official release)", which reads as a statement of descent; it is an ordering position, and the renumbering of 2026-08-04 proved the difference expensive. Putting the February 2026 build at 26.100 and appending the May build as 26.101 made the second, by that reading, a hotfix of the first, so it inherited eight February-only commands and the emitter wrote them onto a May script that the solver reports as deprecated and refuses. Whether a build carries its base release's command evidence is now stated per build in the registry, and the layer that reads the fact asks the registry rather than the version object. FR-02c's cause is corrected in the same pass: the vendor reuses a release name across builds and not only across the hotfixes of one release, which is why "26.1" is ambiguous between two separate releases, and the refusal names each candidate by the vendor build number its solver prints rather than by a hotfix ordinal that is wrong for that pair |
| 1.16.0 | 2026-08-05 | The document catches up with two edits made to its own body in the v0.5.0 development window, both of which changed a requirement's meaning without a version bump, which is the omission this history exists to prevent. AD-05 gains the [manual] extra with its licence card (reports/RPT-017), so the architecture chapter stops listing three optional dependencies where the package declares four. And the command-line surface is five entry points rather than four, pyfs-manual being maintainer tooling that compares a vendor manual against the command database. FR-44 is RESTATED in the same pass rather than merely renumbered: it read "four documented console entry points" and a count in a requirement goes stale the first time the package grows, which is what happened here, so it now asks for one documented entry point per operational concern and carries no number. The reference list also gains SRC-741, the February 2026 manual edition, and stops describing SRC-725 as "the 26.1 manual edition" now that two documents answer to that name |
| 1.15.0 | 2026-08-04 | Two documents catch up with the release they describe, both found by the full-scope audit the release skill requires before the tag and neither reachable from a diff, which is why five review rounds had not seen them. The roadmap's Delivered table stopped at v0.3.0, so the authoritative public requirement document did not record that v0.4.0 exists; it now carries the release with its content named. And the supply-chain row of the standards backlog still read as wholly aspirational after this release put most of it in force: trusted publishing by OIDC with no stored token and never a manual upload, every action pinned by commit digest rather than by tag, least-privilege permissions with the OIDC token requested only by the publishing job, and a release that builds once, records the wheel digest, tests that wheel on four legs and refuses to publish anything whose digest moved. The row is kept on the aspirational table rather than moved wholesale, with what genuinely remains (the OpenSSF badge and a Scorecard run) stated as the residual, because a row that claims completion it has not reached is the defect this release spent five rounds on |
| 1.14.0 | 2026-08-04 | FR-39's third-guard paragraphs are rewritten, and this row also covers the earlier edit of 2026-08-03 that changed them without one, which is the omission that made a version bump owed twice over. Three things are stated that were not: the walk was widened twice more, to the modules declaring no __all__ and then to reachability through a module-private helper, taking the measured population from 70 sites to 137; 24 of them remain and are named one by one in a ratchet, so the requirement stops claiming a clause it does not cover; and the residual sentence is corrected from "any site not on that list fails today", which was false as written, to any site THE WALK REACHES, because a definition omitted from its own module's __all__ is invisible to it. That limit is now measured rather than suspected: nine such definitions exist across the 52 public modules and exactly two held a bare raise. One, qa.physics.read_physics_report, is fixed in this same change, the four sibling refusals in its only caller having raised QaEvidenceError all along. The other, script.solver_setup.build_setup, is reachable only cross-module and its RuntimeError reports the package's own flag table lagging the command database; pricing the fourth widening is v0.5. The published count 114 is corrected to 113, which is what 70 plus 43 gives and what closes against the residual of 24. The widening paragraph also stops saying except PyflightstreamError catches "the package": it catches the CATALOG, and the difference between those two words is exactly the residual this requirement discloses below them. That correction reached four other homes in the same session, the base exception's docstring, the catalog module's docstring, the House conventions register and the release note, all of which had carried the universal form; a fifth sweep then found that all four claimed the ratchet names EVERY surviving bare raise, which this requirement denies by name, so each now states the walk's reach instead |
| 1.13.0 | 2026-08-03 | FR-37 is RESTATED, not merely closed. The first closure kept the original wording, "a status distinct from a completed one", and argued that COMPLETED_MAX_ITER satisfies it because the package treats it as a non-success; a review pass measured that this is the requirement met under a reading rather than as written, since the delivered value is called completed. The text now asks for a status distinct from the CONVERGED one, which is what the library guarantees and what two of the six values give: COMPLETED_MAX_ITER for a run that reached its cap, and FAILED_INCOMPLETE_OUTPUT for one whose loop did not complete at all. The restatement is disclosed in the requirement mapping, which is this project's convention for exactly that, and FR-46's cross-reference stops presenting the collision as open. The residual is recorded rather than fixed: COMPLETED_MAX_ITER reads as a success on first meeting, and renaming it is a manifest-visible break with no functional gain |
| 1.12.0 | 2026-08-03 | FR-37 moves from pending to implemented, resolving the collision it and FR-46 have carried since 2026-07-27. The reference call: the terminal status set stays closed at six and FR-37 closes as covered, rather than opening the set to a seventh value. The requirement now records the reasoning and not only the conclusion, because its own wording pulls the other way: COMPLETED_MAX_ITER is not a success value in this package, it says the solver reached its iteration cap, and a non-finite residual is FAILED_DIVERGED, so the two ways of not converging are already distinguished. It states TWO branches rather than one, which is the correction the closing analysis owed: judging COMPLETED_MAX_ITER as covering this requirement does not reach the forced-iterations early stop, whose loop did not complete and which is FAILED_INCOMPLETE_OUTPUT, also distinct from a completed status. Closing on the one-branch reasoning would have left the second case satisfying the requirement by accident. The naming residual is recorded rather than fixed: COMPLETED_MAX_ITER reads as a completed status on first meeting, and renaming it is a manifest-visible break with no functional gain, so the package explains the name where a user meets it |
| 1.11.0 | 2026-08-03 | Two requirements move on the independent review REV-010, and both move TOWARD what the code does rather than away from it. NFR-07 is narrowed (REV010-013): it promised inputs and invocation reproducible from the manifest entry ALONE, while RunRecord stores hashes and paths rather than content and reconstruct() requires the workspace and refuses when the staged script is absent, which a test pins deliberately. The requirement now states the contract that is kept, entry plus the preserved artifacts it identifies and verifies by hash, and names entry-alone reconstruction as a possible future capability rather than deleting the idea. NFR-18 moves from pending to implemented (REV010-017), in the opposite direction from every other correction in this review: it read "the manifest carries no version field today" while RunRecord.manifest_schema had been live since c7cfdad, so the document understated what the package delivers. Its text also records what REV010-014 changed underneath it, that an absent schema is None meaning predates the field rather than defaulted to the current value, and that such a row is refused rather than reconstructed. NFR-01d's paragraph order is corrected in the same pass: its dated evidence note sat above the statement, and the index generator publishes the first non-italic paragraph, so the external dashboard received the note as the requirement and the statement was published nowhere |
| 1.10.0 | 2026-08-03 | NFR-25 moves from pending to implemented and NFR-13 records a partial delivery. NFR-25 was pending on three sites raising three exception types with three hand-written install remedies and no test exercising any of them; there is one type now, the remedy is composed from the extra's own name rather than written, and a test asserts the shape per extra while an AST guard refuses any raise that writes the remedy by hand. NFR-13 stays PENDING and says why in its own text: the published index now carries status, evidence and a verification method per requirement where it published id, text and priority alone, and a requirement marker plus a ratchet now hold every trace to a live identifier, but 96 requirements exist and the marked set is a fraction of them. Marking a requirement on a test that does not falsify it would be worse than leaving it unmarked, because the index would then count a trace that is not one, so the set grows one verified pair at a time |
| 1.9.0 | 2026-08-03 | NFR-27 is added and NFR-01d's evidence line is corrected, both from the review finding about what CI did not do. NFR-27: a static type checker runs over the package, as a RATCHET rather than a clean adoption, because the first run reported 223 errors in 21 of 53 modules and a blanket adoption means either rushed annotations or a permanently red check. The 21 are exempted by name, so the exemption list is the debt and a newly dirty module fails today. It states in its own text that py.typed is deliberately not shipped and why: shipping it tells every downstream checker to trust annotations that 223 errors say are not trustworthy, and PEP 561 is promised nowhere here, so nothing is broken by the absence. NFR-01d claimed the executable examples ran in CI under Sybil, and Sybil runs docstring doctests and markdown code blocks: the four examples/*.py were in no CI step at all, so the badge rested on a mechanism that did not cover them. A tier-1 test now runs each one and holds it to the extras it declares. The new drift guard added yesterday caught this very edit, refusing the chapter list until its announced NFR range moved with the addition |
| 1.8.0 | 2026-08-03 | The SRS stops being the only judge of its own shape. A tier-1 module now derives the identifier set with the same parser that writes the machine-readable index, and asserts the chapter list's announced ranges, the acceptance mapping's citations, the roadmap's backlog citations, identifier uniqueness across every box kind, and that the document version matches the newest revision row. It found a seventh drift instance on its first run, beyond the six the review listed: the acceptance mapping recorded an accepted item against FR-43 and no FR-43 box had ever been written, so an acceptance existed with no requirement anywhere. FR-43 is therefore added rather than the mapping row deleted, deferred, with its acceptance band deliberately unnamed because the sister library computes the imbalance and returns no criterion, and setting the number is the numerical-analyst seat. What the module deliberately does NOT assert is the CHANGELOG's historical counts: a released section records what happened on a date, and correcting one is a factual judgement about a past acceptance rather than drift |
| 1.7.0 | 2026-08-02 | Two non-functional requirements move, both from the same review finding about what CI does not do. NFR-05 gains the Windows leg: it has always said Windows is the primary execution target, because the solver runs there, while CI ran on Linux alone, so the platform every user is on was the one platform nothing tested and a Windows-only break could have reached a release with every check green. NFR-16 moves from pending to implemented, its floor having been pending on a first measurement that nobody had taken: the tier 1 suite covers 6774 statements with 515 missing and 2058 branches with 213 partial, a branch-mode total of 90.69 percent. The number is deliberately NOT written into the requirement. It lives in the build configuration, where the tool that enforces it reads it, so raising the floor is one edit rather than two statements drifting apart, and the requirement states only the rule and how the floor is set: below the measurement, as a ratchet against regression rather than a target, on one CI leg rather than four |
| 1.6.0 | 2026-08-02 | FR-49 is added, from the review's finding that registering a version made every public surface call it supported. The word covered four states, and the distance between two of them was measured: 26.000 is registered, is accepted by Script and by a campaign, and carries evidence for zero of the database's commands, so nothing whatever can be built for it. Support is now four derived named values, ascending from registered through documented and verified to operational, none of them declared in a file. operational is the one whose claim is checked by performing it: a minimal workflow from geometry to a loads file is built, in a tier 1 test, for every version reported at that level, which is also what separates it from verified. The README's version table stops being prose and is pinned to the derived values by a test |
| 1.5.0 | 2026-08-02 | Session PFS-B1 continues into the independent review's findings, and the chapter they land in is new: "Independent review remediation". FR-48 is added, for the one command status the emitter never acted on. broken is backed by a probe that WATCHED the command fail, and emitting such a command was silent: unlike an absent command, which produces no run, a broken one produces a complete run with wrong numbers in it, which is what AIR_ALTITUDE on 26.120 does: the observed density at 5000 m was the 5000 foot standard state, so the METERS argument read as ignored. Emission now refuses, with one documented way through that records the command, the version, the committed report and the caller's justification in the script and in the run manifest. Two of this repository's own goldens were pinning that mistake and stopped: the actuator polar pinned a 1000 m request the solver was measured not to apply as metres, and the rotor unsteady pinned a script the solver aborts a third of the way through. Note what this row does NOT do: the index prose above has announced the range as ending at FR-48 since revision 1.3.0 while the highest requirement was FR-47, and this addition makes that sentence true by coincidence rather than by a check. The drift finding it belongs to (a parser that derives the identifier set and asserts the prose, the counts and the roadmap against it) is untouched and still open |
| 1.4.0 | 2026-08-02 | Session PFS-B1, three lanes. One requirement added and three moved. FR-02c is new: the vendor ships every hotfix build of a minor release under the one release name, so a display alias can name more than one registered build, and resolution now refuses such a name with every candidate named rather than returning one of them. That makes the vendor name a breaking input, which is accepted because the alternative is handing back a solver build the caller did not choose. FR-02a is amended to match, since it promised that a user may write the vendor name. FR-39 moves from pending to implemented: the package base exception it was pending on exists, every exception descends from it, and each keeps its standard-library base so nothing that used to be caught stops being caught. NFR-14 moves from pending to implemented: research geometry entering the repository was enforced by discipline alone, measured so on a real case (a mesh added under examples/ passed the whole tier-1 suite and the CI guard job), and is now refused by a tier-1 walk over every tracked path plus a pre-commit hook. NFR-14's residual is stated in its own text rather than left to be discovered: the guard keys on extension and cannot see geometry carried in a generic container |
| 1.3.0 | 2026-07-27 | Phase 5 consolidated: the reference acceptance batch is now written in full rather than in part. Thirty-six identifiers are added, counting each split letter as the identifier it is: nineteen whole ones (FR-37 to FR-42, FR-44 to FR-47, NFR-13 to NFR-18, NFR-21, NFR-25, NFR-26) plus seventeen split letters (FR-02b, FR-22a/b/c, FR-30a/b/c, FR-31a/b/c, FR-33a/b/c, NFR-01a/b/c/d). The nine accepted rewords are performed (FR-06, FR-08, FR-10, FR-11, FR-20, FR-26, FR-31, NFR-07, NFR-08; the brief counted ten by including FR-02b, which is a split), and the three remaining single-home edits land, so FR-05 cites AD-03 and FR-09 cites AD-04 rather than restating them. C7 is NOT given an identifier: acceptance it folded under the post-processing line, so the probe-data writers are recorded in FR-21 where the owning seat put them. The reserved-identifier convention is retired by writing the requirements it held. Two acceptances of the same batch are recorded as CONTRADICTING each other, FR-37 against FR-46 over whether the terminal-status set opens to a seventh value, which is the product owner's call and is stated in both. The set is published as a machine-readable index with its traceability numbers, and the mapping from each accepted item to its identifier is recorded so the check is re-runnable |
| 1.2.2 | 2026-07-27 | Two further seat answers about the v0.4.0 breaking window. NFR-20's list of accepted consequences is opened rather than left closed at two, and gains the third: v0.4.0 also converts optional parameters of the tabular layer to keyword-only, which is a public PARAMETER breaking in a minor with no warning release, the same posture applied to the element kind NFR-20 names second. The run row's frame column is deliberately NOT renamed, which changes no requirement text: once the functions lose the pandas sense of the word, the column's name means what it says, and NFR-19's stability promise is kept rather than spent |
| 1.2.1 | 2026-07-27 | Three seat answers taken the same day the batch landed, each closing a question the batch itself raised. NFR-20's 0.x bounds (a break lands only in a minor, a patch never changes the public surface) are confirmed as the design decision, so the provenance qualifier that marked them as a review proposal is removed. NFR-19 stops naming an open half: the column schema is documented in the source module and the docs site will not gain a rendered API reference for its sake, which is now the requirement's stated position rather than a gap, and the corresponding roadmap line is withdrawn. The v0.4.0 rename window additionally takes to_dataframe to to_table, so no name in the results layer survives the substrate change describing a library it no longer returns |
| 1.2.0 | 2026-07-27 | The reference Phase 4 acceptance batch begins landing, and with it one architectural move: pandas and xarray leave the runtime set at v0.5.0 and the sister library becomes a core dependency. AD-06 restated (invalidated, not adapted), AD-07 restated from a future optional extra to a core dependency, AD-05 stops restating the dependency set, NFR-06 gives the set one home with the release that changes it, and five requirements are added: NFR-19 (result column-schema stability, written substrate-neutral, separating universal documentation from a scoped stability promise and naming what the promise excludes), NFR-20 (deprecation policy: it states in its own text that it governs from 1.0, which supersedes the 2026-07-23 answer that had put a deprecation cycle on the run_frame/sweep_frame rename; that from 1.0 the removal itself lands in a major release, so it cannot be read against NFR-04's SemVer commitment; that within 0.x a break lands only in a minor and never in a patch, a bound codified by the API-design review and awaiting the reference confirmation, which arrived the same day, see 1.2.1; and that its code-enforced half covers module shims only. Its status is pending, because the policy does not bind until 1.0), NFR-22 (dependency version envelope, with the pre-1.0 pin form, the Python-ceiling propagation that no requirement covered, and NFR-02's license-evidence obligation for the new core dependency), NFR-23 (layering guard, accepted as this package's own rather than a mirror) and NFR-24 (software jargon glossed, with the glossary rows it requires). The conventions section gains the rule that distinguishes an implemented requirement with a named open half from a pending one whose mechanism already ships, and NFR-11 gains the home-of-record clause that covers a copy which can be neither generated nor linked |
| 1.1.3 | 2026-07-23 | FR-33 gains the per-point output-name rule: a case whose sweep points would render the same output name is blocked before it runs, because they share one simulation folder (incident INC-20260723-2113) |
| 1.1.2 | 2026-07-23 | FR-22 restated after a re-reading of the manual page (SRC-003 p.202): the vorticity CDi selection is an optional input, leaving it unset is the documented solver default (surface pressure integration on every boundary) and is recorded in the solver-setup snapshot rather than refused, and the snapshot states unknown on a version without recorded evidence for the command (PLN-075) |
| 1.1.1 | 2026-07-23 | Standards alignment updated: the docs toolchain row moved to ProperDocs after the green drop-in test (this row also repairs the missed increment of that edit), the Sybil vehicle recorded on the executable-examples backlog row, and the pyproject metadata row updated for the landed classifiers and URLs |
| 1.1.0 | 2026-07-23 | Role-based review model added to the standards alignment; AD-07 co-development with ITACA added to the architecture chapter, with the sister library page and the ITACA adapter open line |
| 1.0.0 | 2026-07-22 | First public edition: the founding requirements (FR-01 to FR-29) updated with implementation statuses through v0.2.0 and the v0.3 line, plus the usage-feedback requirements (FR-30 to FR-36) and the documentation-currency policy (NFR-11) |
Glossary¶
The software terms below are here because this document declares a readership of aerodynamicists rather than software engineers, which makes unexplained software jargon a clarity defect (NFR-24).
| Term | Meaning |
|---|---|
| Campaign | A declared set of simulations sharing a FlightStream version, executable, and workspace |
| Clean-room | Written from the vendor manual and from probe evidence alone, never by reading another implementation; the rule that keeps this package free of the AGPL-3.0 licensed predecessor named in the introduction, whose license would otherwise reach this code |
| Command database | The machine-readable registry of FlightStream script commands with per-version evidence |
| Escape hatch | A deliberate way out of the validated path (here, emitting a raw solver line the builder does not model), allowed but recorded so its use is visible |
| Golden | A committed reference output a test compares against byte for byte, so an unintended change to generated text fails loudly |
| Manifest | The append-only runs.json record that is the sole authority on run identity |
| Probe | A minimal solver run asserting one command's real effect on a licensed machine |
| Round-trip | Writing a structure out and reading it back, asserting the result equals the original; the test that proves a writer and its reader agree |
shell=True |
A Python option that hands a command to the operating system shell to interpret; refused here, because it makes a path containing a space or a quote behave as syntax |
| Shim | A thin stand-in left at an old name so existing code keeps working after a rename, warning as it goes; it is removed at the version its warning names |
| SIM | The native unit of work (a simulation case with a sim_id); the run-matrix vocabulary uses POLAR/POL |
| Substrate | The library the values physically live in (today pandas for tables and xarray for labeled fields), as distinct from the shape they are arranged in, which is what a requirement promises |
| Tidy table | One row per observation and one column per variable, the shape FR-32 converts every parser result into. The substrate holding that shape is pandas today and changes at the migration release, number unset (AD-06); the shape is what the name means, not the library |
| Tier 1/2/3 | The QA ladder: CI-runnable tests / licensed command-validity probes / licensed physics regression |
| Workspace | The managed folder tree owning inputs, runs, and post-processing outputs |