Read the glossary on a phone, and file the code the way the pages are filed - #505
Conversation
Starlight served the 146 API pages on /es/ under its own notice, "Esta página aún no está disponible en tu idioma", which promised a translation that is not coming. The reference is generated from the docstrings, so its text is the code's own; keeping a Spanish copy of it in step with every signature change would cost more than it teaches, and the guides carry the teaching in both languages already. So the notice now says what is true: the API reference is published in English in both languages because it is generated from the code. The Spanish reference index says the same where it sends the reader there, and the parity check, which exempts exactly this subtree and nothing else, records the reason rather than the mechanism.
Every guide opened with "By José Manuel Requena Plens · Published ..., updated ...", between the title and the first sentence, on 278 pages. Of the three things it said, two were already on the page: the name in the footer credit, which carries rel="author" and is the form a crawler reads, and the update date in the last-updated line at the foot of the article. Only the first publication date was unique to it. So the line is gone and that date moved to where its sibling already was. The last-updated line now reads "Published <date>, updated <date>", one date when the two are the same day, in both languages. Nothing machine-readable changes: Head.astro computes author, datePublished and dateModified from the same git history and the same route data whatever the body shows, so the JSON-LD, the sitemap, the markdown copies and the llms artifacts are untouched.
On a wide screen the sidebar answers "what is in this topic?" before the reader asks: /signals/ opens with its seven rows down the left. On a phone the same page opens with a title and prose, the sidebar folded behind the menu button, and nothing on the first screen names a single section. The list is further down every landing page, authored as headings, but measured against the built site it starts between one and nearly three screens below the fold. So the landing page now opens with it. TopicSections renders the topic's own sidebar tree as a short navigation block: one row per section, with the number of pages inside, the whole row a target. It renders on a topic's landing page and nowhere else, and `md:sl-hidden` retires it the moment the real sidebar appears, so a desktop reader is not shown the same seven labels twice. The tree it reads is the one the sidebar renders, not a second list to keep in step: the topics plugin has already narrowed `starlightRoute.sidebar` to the current topic by the time components render, which is the same data Pagination.astro walks.
The Spanish-regulation guide printed the snippet that renders an acoustic inspection fiche and then showed no fiche, unlike every other guide that ends in a report. It was not alone: sixty-seven fiches are generated, committed and shipped in the built site, and seven of them were embedded on no page in either language. One was the worked example of the very snippet its guide prints. The seven are in their guides now, in both languages: the RD 1367/2007 inspection fiche, the ISO 1999 NIPTS and HTLAN predictions, the machine enclosure and HVAC duct fiches, the reactive silencer, and the IEC 61400-11 tonality assessment. Three of those guides never mentioned `.report()` at all, so they gained the paragraph and the snippet as well as the preview; every number quoted in a description was read off the committed page. The gap was invisible to every gate, which is the part worth fixing. The fiche check closed the loop from the generator to the committed file and stopped there, and the EN/ES parity check compares the two trees with each other, so a fiche missing from both languages passed both. It now asks the remaining question, per language: is this fiche on a page a reader can reach, and does every embedded name exist?
The glossary was twelve five-column tables. A table is the right shape for numbers and the wrong one for a sentence: measured on a phone, the definition column rendered 135 px wide while the one-word guide link took 256, and the row needed 775 px of horizontal scroll inside a 358 px screen. The definition is the content of that page, so each term is a block now: the notation and its unit above, the sentence at the full width of the column, the standard and the guide underneath as metadata. The definition gets 324 px on the same phone and there is nothing to scroll sideways; on a wide screen the spare width goes to a second column instead of stretching the prose. The deeper problem was that the same 120 entries existed four times: a table in each language, and a hand-written JSON-LD block of 120 DefinedTerm nodes in the frontmatter of each. Nothing kept the four in step and they had drifted. They come from one array now, src/data/glossary.mjs, which the component renders and emits the structured data from. Each page went from 2030 lines to 39. What cannot differ between the two languages is stored once, which is what stops it drifting: the notation, the designation where it is only a catalogue number, the route of the guide. What genuinely translates is a pair: the definition, the unit where the unit is a word, the clause, the twenty-one designations carrying translated prose, and the two entries named rather than symbolised. The link to a guide now takes its text from that guide's own title, read at build time, so the nine Spanish rows still advertising a title their page had stopped using are gone by construction, and a term pointing at a page that does not exist fails the build instead of shipping a dangling link.
The page stopped being twelve markdown tables and became a component, so it is now the kind of page pa11y exists for. It was not on the list; the other two generated reference pages, conformance and errata, were.
Three result classes had a `.report()` section written in their guide and no example to show for it: the two detailed ISO 12354 predictions and the ISO 3745 precision sound power determination. The guide told the reader what the fiche contains and could not show one. The two prediction fiches are the Annex L / Annex G building, read from the fixture the tests and the conformance report already share rather than transcribed a third time: the same 220 mm separating floor, floating floor, AAC external walls and calcium-silicate internal walls, through the same eight Annex E junctions. They rate to the annexes' own R'w = 57 dB over thirteen paths and L'n,w = 41 dB over five. The two corrections the registry records against the printed inputs travel with the fixture, so the fiche cannot quietly disagree with the conformance rows. The precision fiche is the guide's own worked example, the forty-position hemisphere array whose spectrum the page already plots, so the fiche and the prose print the same LWA = 89.3 dB(A) and the same U = 4.1 dB. All three are embedded in their guides in both languages, which is what the per-language check added with the previous batch now requires of every committed fiche.
The new precision snippet wrote emission.ReportMetadata; the class is exported from the package root, as its sibling snippet on the same page already showed. The static pass does not import anything, so only CI, which runs every English block, could see it.
Six findings, four of them mine and two already fixed by the snippet commit. Three entries had their designation cut mid-parenthesis. The migration split a standard at the first comma when what followed looked like a clause, and in "ISO 717-2:2020 (measurement in ISO 16251-1:2014, Formulae (3) and (4))" what followed was the middle of a note: the opening bracket stayed in `standard` and the closing one moved to `clause`. The page read correctly because the component joins the two with a comma, and the structured data did not. Those three notes are one field again. Two entries kept their clause inside the designation, which every other entry separates and which the JSON-LD needs separated. The migration's rule required a word boundary after the first digit, so it matched "5" and missed "14.12.7". The underwater sound pressure level stored its notation twice, `$L_p$` in English and `Lp` in Spanish, so one card typeset it and the other printed the source. The notation is one value with a translated qualifier, which is what the module's own header says. In the component, the site and base strings come from src/data/site.mjs, where astro.config.mjs and the audit scripts read them, instead of a literal; the guide URL is built from the slug rather than by stripping the base back off a href, which a string replace would have removed wherever it first appeared; and the JSON-LD description, unit and clause go through the same maths stripping as the term code, so a consumer reads "THDF" and not the TeX.
Five files held 44 663 lines between them, and none of them held one subject. scripts/generate_graphs.py was 21 020 lines with 301 figure builders, a 2 100 line translation table, an animation encoder and a schematic drawing vocabulary sharing one namespace; scripts/conformance_report.py was 529 checks over 57 domains; scripts/generate_diagrams.py, 84 drawings. tests/reference_ data.py was 641 constants under 137 banners, and _plot/geometry.py was the one module in that layer cut against its grain: every other _plot module is one domain, that one was every domain's setup drawings. They are packages now. The three scripts keep their entry point, so `make graphs`, `make conformance` and the two test modules that import them by name are untouched; generate_graphs.py goes from 21 020 lines to 689, conformance_report.py from 9 479 to 175, generate_diagrams.py from 7 645 to 28. reference_data and geometry became packages of the same name, so no importer changed at all: their `__init__` re-exports every name explicitly. Each figure went to the module named after the guide that embeds it, resolved mechanically by matching every save_figure stem against the images the site pages reference; each check went to the module named by the banner it already sat under, and that import list is now the report's section order, stated as such. The nine diagram builders called `_d1` to `_d9` are named after what they draw, which the registry key already knew. A split is a move, and the proof is that nothing it generates moved: the conformance report regenerates identical, 336 diagram SVGs and every figure variant checked come out byte for byte the same, an AST comparison of all 543 top-level definitions of the figure generator finds 541 untouched, and the suite passes 8 010 tests. The two functions that did change are set_lang and set_theme, which now push their rebindings into the package so that not one figure body had to learn where its palette lives. The rule this followed is written down in CONTRIBUTING.md, because the number everyone reaches for is not the criterion: PEP 8 sets no file limit, pylint and Sonar both set 1000 and then hedge it (pylint's own config raises it to 2000 and disables the checker; S104 is not in Sonar's default profile), and ruff has rejected the rule twice. What matters is whether the file is one subject. Seventeen modules over 1000 lines were judged and left alone for that reason, most of them half docstring about one clause.
Each of these files had reached the point where its docstring opened by announcing two standards. The split follows the seam the prose already described, so every new module is one subject: - emission/sound_power.py keeps ISO 3744/3746 and hands ISO 3745 to sound_power_anechoic; the ISO 9614-3 block joins Part 2 in sound_power_intensity, which is the same method at precision grade. The floor the three standards share is in emission/_shared.py. - aircraft/rotorcraft_noise.py keeps the source model; the ground, terrain and atmosphere adjustments go to rotorcraft_propagation. - materials/absorbers/porous.py keeps the equivalent-fluid and resonant-sheet building blocks; the transfer-matrix stack goes to layered. - materials/absorbers/impedance_tube.py keeps ISO 10534-2; the ASTM E2611 four-microphone method and the ISO 10534-1 standing-wave method get their own modules. - materials/diffusers/scattering_diffusion.py keeps ISO 17497-2; Part 1 goes to reverberation_room_scattering. - signals/spectra.py hands the multitaper estimator and the window metrics to modules of their own. - electroacoustics/distortion.py keeps harmonic distortion; intermodulation and the noise measurements separate. - filters/compliance.py keeps the band filters; the weighting-curve verification goes to weighting_compliance. - building/measurement/insulation.py hands the single-number ratings to ratings; building/prediction/resilient_layers.py hands the wall linings to linings. The test files split the same way, and the flat top-level API is unchanged: the same 1270 names resolve, from new modules. docs/CONFORMANCE.md regenerates byte for byte identical, which is what makes this a move rather than a rewrite. A deprecated 3.x module path serves whatever its target module exports, so a name that changes module inside its package would have stopped resolving through it, in a release where the alias still promises a warning instead of an ImportError. _compat.py now knows which modules a split fed, and a test holds every name to that promise.
The figure and fiche generators were the last files where one module answered for a dozen unrelated drawings. Each split follows a seam that was already there, and no builder body changed: - scripts/generate_reports.py drops from 3573 lines to the registry and the command line, over a new scripts/reports/ package of one module per subject. The 70 fiches keep their order, and `python3 scripts/generate_reports.py` is invoked exactly as before. - scripts/figures/fields.py becomes a package: one module per simulated subject over the shared capture and display-gain core. The field builder and the clip that renders it stay together, because the field is memoised and the four language and theme variants fork off one computation of it. - scripts/figures/building.py gives the room acoustics figures a module of their own and separates what a built element measures from what a design predicts. - scripts/figures/signals.py separates filtering and weighting from spectral estimation, from correlation and envelope analysis, and from the measurement-quality tests. This also fixes a figure that could not be generated at all. The Annex L path builder reaches into tests/ for its worked example, and it locates that directory by counting parents from its own file. Moving it down into the package left the count one level short, pointing at a scripts/tests that does not exist. It now counts from the same anchor scripts/conformance/registry.py uses, and the comment says why the shorter form is wrong here. Every figure regenerates within tolerance and every fiche byte for byte, which is what makes these moves rather than rewrites.
An audit of the layout after the module splits turned up eleven things filed where they do not belong. Four of them are damage the splits themselves did: - hooks/pre-commit watched tests/reference_data.py and scripts/conformance_report.py, but the first is a package now and the 25 domain modules moved to scripts/conformance/, so the hook had quietly stopped regenerating the conformance report for most changes that need it. - CONTRIBUTING told contributors to add a generate_* function to scripts/generate_graphs.py. That file holds no functions any more, and the catalogue make graphs walks is in scripts/figures/registry.py, so a figure added where the guide points is never drawn. It now names the builder module and the registry for each of plots, diagrams and fiches. - _plot holds one renderer module per domain; _plot/junction.py was the only one named after a single result, while the geometry drawing for that same result already sat in _plot/geometry/vibration.py under the rule. Folded into _plot/vibration.py. - Two byte-identical PNGs sat at the repository root, referenced by nothing. Six tests move to directories that already existed and already carried their subject: the filter-bank suites into tests/filters/ and the impact insulation one into tests/building/measurement/. The cross-cutting suites stay at the top level, which is what they are. On the site, the two assessment guides move into environment/assessment/, the directory the sidebar group is named after; the section index had been linking two of its three pages from outside itself. Old links to them break rather than carry a redirect. Six section indexes listed pages belonging to other sections under the literal "Pages in this section" heading: those move to a "See also" list, which is what they were. The aircraft and environment overviews claimed pages from other topics, counted them in their prose, and in the environment case published a section from another topic while hiding its own; both now match their sidebar groups in either language.
|
You've reached the fair usage limit for the Bito Code Review Agent trial. Upgrade to a paid plan or contact support@bito.in for assistance. Learn more |
|
Important Review skippedToo many files! This PR contains 372 files, which is 272 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (11)
📒 Files selected for processing (372)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The airport-noise guide computes an event level from a noise-power-distance table and a flight path that it writes out by hand, which is what you want while learning ECAC Doc 29 and never afterwards. The EASA ANP database of real aircraft types has shipped with the package all along, and `anp_fleet` bridges it into the Doc 29 chain, but no guide said so: it appeared only in the generated reference, where you have to already know the name to find it. It now has a page in both languages and in the plain-markdown edition: opening the shipped database or another CSV export, what one aircraft record holds (metadata, the power parameter its NPD table is indexed by, the curves per operation and metric, the default trajectories), reading and interpolating the NPD surface, and running the single-event level and the ground-grid contour straight from an aircraft identifier. It states the limit the module documents but nothing user-facing did: only fixed-point profiles are read as ready-to-use trajectories, which is 13 of the 155 aircraft, because the rest describe their departures as procedural steps that need a flight-mechanics model to fly. NPD curves are tabulated for all of them. Two figures come with it, drawn off the real 747-100 record rather than a schematic table. The renderers behind those two `.plot()` methods lived in `anp_fleet` itself, with a translation table of their own, while every other aircraft result draws from `_plot/aircraft.py`. That is the same rule the junction renderer was moved under, so they move there too, keeping their Spanish output through the `_t` table the destination already uses. Two of their seven labels were already in it, translated identically. They also arrive named `plot_anp_npd` and `plot_anp_profile`, in step with the eleven `plot_*` renderers beside them and distinct from the existing `plot_npd_level`.
|
You've reached the fair usage limit for the Bito Code Review Agent trial. Upgrade to a paid plan or contact support@bito.in for assistance. Learn more |
Say which field the chain reads. The guide introduced the aircraft record as carrying "the metadata the Doc 29 chain needs downstream" and then listed the engine type, the engine count and the weight class. The chain reads none of those. The one field it does read is the engine mounting, which the page never mentioned: it selects the engine-installation correction, it is one of wing, fuselage or propeller, and the shipped fleet splits 70 / 55 / 30 across the three, so the choice moves the answer. All three editions now say so, and the record print shows it where the record is first opened. Fix the guides map, which a gate was already failing on. start/guides.md counts its own entries in figures and in words, and check:guides compares both against the pages that exist. Adding a page without updating it left six failures in the two languages. The rest is the new code drifting from what its neighbours do: - The Spanish profile figure published its axis labels and its legend in English. The library's own string table had the translations, but a figure is translated at savefig time from the table in scripts/figures/i18n.py, and only the title and the annotation had been added there. Its two NPD labels were already present for the Doc 29 figure. - Neither renderer called localize_axes, so a Spanish axis kept a decimal point where all eleven of its neighbours give a comma. - Neither took the family signature: every other renderer in the module defaults ax to None and language to "en", so these two could not be called the way the rest can. - They drew with raw literals, a grey "0.4" for the NPD nodes and "tab:red" for the runway points, instead of the shared palette the module imports. - A section banner left behind in anp_fleet.py still announced plotting "local to this module so the shared _plot string tables stay untouched", which is the opposite of what moving the renderers did. - The two figure builders were registered at the head of _FIGURE_FUNCS. That tuple is grouped by subject under banner comments, so they now sit with the Doc 29 figures they extend. - See also had no API-reference bullet, the only aircraft guide without one; "What this guide covers" was a bullet list instead of the site's covered and not-covered pair, so the page never stated that procedural-step profiles are out of scope; the plain-markdown edition carried neither figure; the section index counted four pages while its narration still walked three; and the Spanish called NPD "ruido-potencia-distancia" where the rest of the Spanish site says "nivel-potencia-distancia".
main carries the squash of #504, which is this branch's own glossary work under a different SHA, so most of it merged cleanly. Four files needed a decision, and in each one this branch is the later state: - `site/src/data/glossary.mjs` differed in three lines, the guide slug of the two assessment pages this branch moved into `environment/assessment/`. - The two `spanish-noise-regulation.mdx` pages differed in the depth of their component imports, which is what that same move corrected. - `scripts/generate_reports.py` is the fiche registry and command line here, and the builders it used to hold live in `scripts/reports/`. The three fiches #504 added are in that package and still registered.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #505 +/- ##
==========================================
+ Coverage 96.99% 97.00% +0.01%
==========================================
Files 272 295 +23
Lines 38575 38787 +212
==========================================
+ Hits 37416 37626 +210
- Misses 1159 1161 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Numerical conformance report✅ 533/533 conformance checks pass across 57 domains and 362 standards - filters class 1 - weightings within IEC 61672-1 class 1. Each row pins a standard clause to its expected normative value and the value the library computes. Every section below is collapsible and stays collapsed while all of its rows pass; a section with any failing row opens automatically. ✅ Numerical validation - filters & weightings: class showcase (IEC 61260-1 · IEC 61672-1 · ISO 7196)IEC 61260-1:2014 class per filter architecture (order 6, one-third-octave, 100 Hz-10 kHz, fs = 48 kHz). For each architecture the table shows, at its binding band, the measured relative attenuation and the class-1 limit it must clear, so the number and the range it must sit in are both visible. A positive margin means the acceptance limits are met with that much room.
Only Butterworth (the library default) and Chebyshev-II are class-compliant architectures. Chebyshev-I and elliptic trade the mask for passband ripple, and Bessel for a maximally-flat group delay (soft rolloff); they cannot satisfy the IEC 61260-1 Class 1/2 attenuation mask by construction, so they are labelled By design - this is expected, not a failure or regression. Frequency-weighting conformance (A/C: IEC 61672-1 Table 3; G: ISO 7196 A.3). The max deviation from nominal is informational (it falls at a frequency extreme where the tolerance is widest and asymmetric); compliance is judged at the binding frequency - the one with the least headroom - where the deviation, the applicable tolerance band and the headroom are shown together.
✅ Filters & weightings: 100% (10/10)
✅ Levels & dosimetry: 100% (9/9)
✅ Room & building acoustics: 100% (72/72)
✅ Room acoustics: 100% (16/16)
✅ Psychoacoustics: 100% (14/14)
✅ Speech transmission (IEC 60268-16): 100% (10/10)
✅ System measurement (Golay / Kirkeby / Mueller-Massarani): 100% (5/5)
✅ Intensity & sound power: 100% (10/10)
✅ Building prediction & uncertainty: 100% (15/15)
✅ Outdoor propagation & occupational exposure: 100% (10/10)
✅ Materials: absorption, airflow & impedance: 100% (6/6)
✅ Scattering & diffusion (ISO 17497): 100% (14/14)
✅ In-situ road absorption (ISO 13472): 100% (3/3)
✅ Precision sound power (ISO 3745 / 9614-3): 100% (4/4)
✅ Human vibration (ISO 8041 / 2631 / 5349): 100% (15/15)
✅ Speech intelligibility (ANSI S3.5-1997): 100% (24/24)
✅ Objective intelligibility (STOI / ESTOI): 100% (3/3)
✅ Impulsive-sound prominence (NT ACOU 112): 100% (2/2)
✅ Impulsive-sound prominence (ISO/PAS 1996-3): 100% (2/2)
✅ Room noise (ANSI S12.2-2019): 100% (3/3)
✅ Hearing threshold (ISO 7029 / ISO 389-7): 100% (3/3)
✅ Measurement uncertainty (GUM / Supplement 1): 100% (7/7)
✅ Noise-induced hearing loss (ISO 1999): 100% (6/6)
✅ Multiple-shock whole-body vibration (ISO 2631-5): 100% (6/6)
✅ Sound absorption in enclosed spaces (EN 12354-6): 100% (2/2)
✅ Prominent discrete tones (ECMA-418-1): 100% (2/2)
✅ Tonal audibility (ISO/PAS 20065): 100% (11/11)
✅ Psychoacoustic annoyance & fluctuation strength (Fastl & Zwicker): 100% (3/3)
✅ Electroacoustics: distortion & frequency response: 100% (20/20)
✅ Calibrated spectral analysis (Bendat & Piersol): 100% (12/12)
✅ Multiple-input coherence (Bendat & Piersol): 100% (5/5)
✅ Time-frequency analysis (Bendat & Piersol): 100% (3/3)
✅ Correlation, time delay and envelope (B&P / Knapp & Carter): 100% (7/7)
✅ Cepstrum, liftering and envelope spectrum (Havelock / B&P): 100% (3/3)
✅ Time synchronous averaging (McFadden 1987): 100% (5/5)
✅ Data qualification and Rice statistics (Bendat & Piersol): 100% (8/8)
✅ Underwater acoustics (ISO 18405/17208/18406): 100% (6/6)
✅ Underwater sound propagation (transmission loss): 100% (16/16)
✅ Underwater propagation regimes (Weston flux theory): 100% (3/3)
✅ Marine-mammal auditory weighting (NMFS / Southall): 100% (4/4)
✅ Underwater numerical propagation (modes / rays / PE): 100% (4/4)
✅ Aircraft noise (ICAO Annex 16 / IEC 61265): 100% (15/15)
✅ Rotorcraft noise (ECAC Doc 32 / NORAH2): 100% (12/12)
✅ CNOSSOS-EU road source (Directive 2002/49/EC Annex II): 100% (6/6)
✅ Wind-turbine noise (IEC 61400-11): 100% (3/3)
✅ Porous & multilayer absorbers (Mechel / Bies / Cox & D'Antonio): 100% (20/20)
✅ Slow-sound perfect absorbers (Jimenez et al. Appl. Sci. 2017): 100% (3/3)
✅ Program loudness (ITU-R BS.1770 / EBU R 128): 100% (8/8)
✅ 2D FDTD wave simulation (Attenborough & Van Renterghem 2021, Ch. 4): 100% (4/4)
✅ Swept-sine distortion & phase utilities (Farina / Novak): 100% (7/7)
✅ Spherical ground & barriers (Attenborough / Salomons / Bies): 100% (7/7)
✅ Panel & aperture sound insulation (Bies / Hopkins / Cremer): 100% (17/17)
✅ Bending-wave plate-junction transmission (Cremer / Craik / Hopkins): 100% (6/6)
✅ Atmospheric refraction (Salomons rays / GFPE): 100% (3/3)
✅ Electroacoustics: 100% (9/9)
✅ Industrial noise control: 100% (22/22)
✅ CNOSSOS-EU railway source (Directive 2002/49/EC Annex II): 100% (8/8)
Tests & coverage — 48204 tests, 0 failures (✅ all green)
Conformance harness: |
|
|
You've reached the fair usage limit for the Bito Code Review Agent trial. Upgrade to a paid plan or contact support@bito.in for assistance. Learn more |



Two threads that ended up depending on each other: finishing the site details I
had left open, and then giving the code the same treatment the pages got.
The site
The glossary was 120 terms spread across markdown tables that read badly on a
phone. It now comes from one source,
site/src/data/glossary.mjs, rendered ascards by a
Glossary.astrocomponent that also emits aDefinedTermSetformachines. Each term carries its symbol, unit, standard, clause and the guide
that teaches it, and the guide link text is read from the content collection at
build time, so a slug that stops existing fails the build instead of rotting.
Three example fiches the guides described but never showed are generated now
(
iso12354_detailed_airborne,iso12354_detailed_impact,iso3745_precision_power), andscripts/check_reports.pygained a per-languagecheck that every committed fiche is actually shown on a page, which is what
found them.
On a phone, a topic's landing page listed nothing it holds;
TopicSections.astronow shows the sections with their page counts. The "By ... Published ..., updated ..."
line moved off the top of every page into the footer, where a date belongs.
The code
scripts/generate_graphs.pyhad reached 21020 lines. Three rounds of splittingbrought the largest file in the repository down to 2862, which is the flat API
surface and cannot be shorter. Files over a thousand lines went from 41 to 40,
and that is the point: splitting a 21000-line file yields several of a thousand,
and what changed is that none of the remaining ones has an honest seam left.
The ten that stay long are the API surface, two translation tables and seven
modules that each hold one standard.
CONTRIBUTING.mdnow states the rule the splits followed: there is no linelimit, the test is cohesion, and a split is a move proven by byte-identical
generated output. Every round is verified that way. The 1692 committed figures
regenerate within tolerance, the 70 fiches byte for byte, and
docs/CONFORMANCE.mdidentically, with its 533 checks passing.
Splitting a module moves names between modules of the same package, and a
deprecated 3.x import path names only one of them, so 47 names would have
stopped resolving through a path that still promises a warning until 5.0.
_compat.pynow knows which modules a split fed, and a test holds every nameto that promise.
What the reorganisation broke, and this fixes
Auditing the layout afterwards turned up four things the splits had damaged and
nothing had noticed:
hooks/pre-commitwatchedtests/reference_data.pyandscripts/conformance_report.py. The first is a package now and the domainmodules moved to
scripts/conformance/, so the hook had quietly stoppedregenerating the conformance report.
CONTRIBUTINGtold contributors to add figure builders toscripts/generate_graphs.py, which holds no functions any more. A figureadded where it pointed would never have been drawn.
tests/bycounting parents from its own file, and moving it into the package left the
count one short.
os.path.dirname(__file__)plus".."climbs one levelless than
Path(__file__).parent, so the two forms read alike and are not._plotholds one renderer per domain;_plot/junction.pywas the only onenamed after a single result.
Filing
Six test files move to directories that already carried their subject, two
guides move into the directory their sidebar group is named after, and six
section indexes stop listing pages from other sections under a heading that
reads as an inventory. Old links to the two moved guides break rather than
carry a redirect.
Checks
8011 tests,
ruff,mypyover 419 files, 3630 documentation snippets across505 pages, 533/533 conformance checks, i18n parity over 156 pages, the site
build and
html-validate.Known gap
phonometry.aircraft.anp_fleetexports five public names and no guide mentionsit; only the generated reference covers it. That predates this branch and I have
left it alone here rather than widen the subject.