Read the quasi-peak value method, not an r.m.s. through its network (#647)
* Read the quasi-peak value method, not an r.m.s. through its network
ITU-R BS.468-4 clause 3 reserves dBqps for the quasi-peak value method,
and NOTE 1 says an r.m.s. meter reading the same network gives figures
that are not directly comparable. The network was already exposed and the
curve landed in #645; the detector itself was missing.
Clause 2 prints no time constant, so the three are solved for against the
eleven reference readings of Tables 2 and 3 rather than quoted. How well
eleven windows pin three constants is measured and stated with the
procedure that produced it, because the answer depends on the question:
with the other two frozen, charge holds from 1.014 to 1.894 ms, discharge
from 233 to 367 ms and the reading device from 96 to 200 ms, so the
reading device is what the tables pin down least.
Four ballistics that all pass all eleven windows still read 2.61 dB apart
on a click and 0.03 dB apart on a steady tone. That is a property of the
standard, so it is documented as a lower bound on any reading here.
Four misprints found on the way are recorded in docs/ERRATA.md, none of
which changes what this library computes. IEC 60268-1:1985 Figure A1
prints the last shunt capacitor as 41.47 nF where BS.468-4 Figure 1a
prints 31.47 nF, and the annex contradicts itself two pages earlier:
against Table AI the printed value breaks that table's own tolerance
column at seven frequencies.
MicrophoneNoise(weighting="CCIR") stays metadata and weighted_thd stays
an r.m.s. through the network; both are now documented as such.
* Key the quasi-peak caches by the ballistics, and remeasure what they identify
The published statement about how far each of the three time constants can
move before one of the eleven windows fails could not be measured. The chain
caches the clause 2.6 calibration factor and the steady 5 kHz reference on the
sample rate alone, and both run through the detector, so moving the constants
left the caches answering with a reference computed for a different
instrument. The symptom was that the same value passed or failed depending on
what order the probes ran in.
It was correct while nothing could change the constants, and wrong for a
module whose documentation publishes a claim about exactly that. The
ballistics now travel through the chain as an argument and into both cache
keys, and verify_quasi_peak_dynamics takes them too, so the claim is
re-derivable rather than a number to be believed.
Remeasured on that footing, all eleven windows hold from 1.02 to 1.90 ms of
charge (1.88), 230 to 370 ms of discharge (1.61) and 96 to 200 ms of reading
device (2.09), each edge a value that conforms rather than one rounded past
the boundary. The earlier figures were taken through the contaminated path and
were wrong in both directions; one published edge did not even conform.
Two things follow that were not said before. The ranges are marginal and not a
box: the fastest charge with the shortest indicator misses by 1.11 dB. And the
spread between conforming instruments is larger than reported, because the
first measurement read the needle before it had finished rising. Sampling the
region and keeping the 243 sets that meet all eleven windows gives 4.61 dB on
a transient, more than the widest window the tables draw, against 0.00 dB on a
steady tone, which is the calibration doing what it promises.
Four tests hold the range from both sides, so it can be neither widened nor
quietly narrowed, and one asks in the order that used to give a wrong answer.
* Build the fixture before the block that expects it to raise
Ten pytest.raises blocks across nine files built their argument inside the
block. If the construction itself raised, the test would pass for the wrong
reason and the call it exists to check would never run. Sonar flags this as
S5778 but only on new code, so eight of the ten would never have been
reported: the two it did report were in a file that happens to be new.
Also removes a redefinition in _plot/signals.py, where _TIME_LABEL and
_LAG_LABEL are each assigned twice at module level. Both pairs carry the same
string so nothing is wrong today, but editing the first has no effect, which
is the kind of thing that is discovered the hard way. A sweep of the rest of
src finds no other case.
* Say on every page that this documentation is ahead of the release
The site documents the tree, which is ahead of what is on PyPI: pages here
describe modules, entry points and names that 3.3.0 does not have, so a reader
who installs the published version and follows a page gets an ImportError and
no reason for it. A standing banner says so.
Starlight's banner is per page, set in frontmatter, and its config-level form
takes one string with no way to vary it by locale. Half this site is Spanish,
so the component picks the text from the route's language. A page that sets
its own banner still wins: that one is about the page, this one is about the
site.
* Say the verdict in words, show how much of each tolerance is spent
The conformance tables marked every row with a tick or a cross, which can only
say two things. There are four verdicts: a check can also be by design, as the
Chebyshev and Bessel architectures are against a mask they cannot meet, or not
applicable. Those two had nowhere to go and were carried in a display string
where nothing could count them. A word says all four, reads the same in a
plain-text diff and needs no colour.
The Markdown report also never showed the number that matters most for a
metrology library: how much of a clause's published tolerance the deviation
actually consumes. The artefact has carried it since the report became
structured data, the site page has shown it, and the report itself did not.
It is there now on 469 of the 566 rows, with the dash on the other 97
explained rather than left to be guessed: those clauses state no two-sided
tolerance, so there is no budget to spend.
The same column appears twice in the PR comment and was explained under the
second table, which the reader reaches after meeting the column under the
first. The note moves to the head of the section.
Two responsive defects, both measured in a browser at a 390 px viewport rather
than reasoned about:
- The domain filter on the conformance page is sized by its longest option,
"2D FDTD wave simulation (Attenborough & Van Renterghem 2021, Ch. 4)", which
asks for 552 px inside a 374 px row. A flex item's automatic minimum size is
its content, so it refused to shrink and took the document to 582 px. With
min-width: 0 it is 390.
- Inline KaTeX had no scroll box, only display math did, and KaTeX never breaks
a formula. One acceleration formula on the errata page is 1011 px wide and
carried that document to 1067 px.
Wide tables were not part of it: they already scroll inside their own
containers, and only looked guilty because getBoundingClientRect reports an
element's full width whether or not its container clips it.
* Draw the verdicts and the count, instead of spelling them in emoji
The report says Pass, Fail, By design and n/a in words now, which fixed the
meaning an emoji could never carry, but left the tables with nothing to scan.
This adds the pictures back as SVG the repository owns and generates: four
verdict marks and a summary banner under .github/badges, redrawn by
`make conformance` from docs/conformance.json so the count on the banner is
always the tree's own. Nothing points at them yet; the documents come next.
A mark is one file with no dark twin, and that is a measured decision rather
than a shortcut. Each fill clears 3:1 on GitHub light, GitHub dark, GitHub dim
and the documentation site's ground alike, so the same file is right in every
theme, the way a shields.io badge has been for a decade. Pairing them instead
would need a <picture> element on every row, which costs 163 kB on the 566-row
table against 9.6 kB for reference-style images of a single-file mark. The
banner is the opposite case, once per page, where the pair costs 278
characters and buys a card that sits properly on its page, so it ships as a
light and a dark variant on the _dark naming the README and ThemeImage.astro
already pair on.
Shape carries the meaning alongside colour: a filled disc, a hexagon, a
rounded square and a hollow ring stay apart from each other in greyscale and
to a reader who cannot separate the hues. Every file states its verdict in a
<title> as well, because an image of a tick is not a verdict to anyone who
cannot see it.
The blue moved off Primer's #0969da, which measures 2.89:1 on GitHub Dim, onto
#1f6feb at 3.24:1. The whole contrast table is measured by the tests rather
than asserted in a comment.
Glyphs are outlines of the committed fonts, as the brand assets already are,
so the shared conversion moved into scripts/svg_text.py and generate_brand.py
now calls it; the brand output is byte for byte what it was. The banner is
drawn ten units to the pixel so every coordinate is a whole number, which
leaves no float to be formatted two ways on two machines. Two runs, three hash
seeds, a different timezone and a Turkish locale all write identical bytes.
Also fixes an assertion left pointing at a tick that no longer renders.
* Say why inline math has no scroll box, having measured what one costs
The commit before this gave inline KaTeX the scroll box display math already
had, on the reasoning that a formula wider than the column should scroll rather
than push the page sideways. The reasoning is right and the fix is not
available: overflow does nothing on an inline box, so the box has to become
inline-block, and that changes how every formula in the corpus takes part in
line layout.
Measured over the 991 inline formulas on the four most formula-heavy pages,
990 of them move. Their x and their width are untouched, but each box grows
from 22 px to 24 px tall, which lifts the line it sits on, and down a long page
the shift accumulates to 3645 px. Every variant gives the same 24 px, because
the growth is inline-block itself and not the overflow: vertical-align baseline,
a negative vertical-align, and dropping the overflow entirely all do. Only
overflow: clip keeps the document height, and it clips the formula instead of
scrolling it, which is worse than the defect.
Two formulas on one page do not justify taxing the typography of the 990 that
are already the right width, so the rule is gone and the comment says why, with
the numbers, so the next reader does not re-derive it. A formula wide enough to
need a scroll box gets fixed where it is written, as display math.
* Draw the verdict beside the word, wherever the report is read
The indicators the last commit generated were sitting in .github/badges
with nothing pointing at them. Now the three places that publish a
conformance verdict cite them, and each does it the way its own renderer
allows.
docs/CONFORMANCE.md gets a mark in front of every Status cell and in the
filter-class showcase, as reference-style images with one definition per
mark at the foot of the document. Measured on the real 566-row table, the
three ways of writing a per-row indicator cost +10.6 kB by reference,
+58.0 kB inline, and +162.8 kB for a per-theme <picture> on every row; the
mark is one file that clears 3:1 on every ground, so the last option buys
nothing. The head of the document gets the summary banner as the <picture>
pair the README already uses, and a legend that lists the marks the page
actually draws. Every mark keeps the word beside it: the word is the
verdict, the picture illustrates it, and the word is what survives a raw
view, a plain-text diff and an image that never arrives.
The pull-request comment gets the banner pinned to the head SHA, so it
reports the branch under review rather than main, and loses the last of the
emoji: the tick, the cross and the warning sign on its own test-status line
are now marks and words.
The site inlines the same four marks as an SVG sprite read off the
committed files at build time, which costs no request and lets the Spanish
page say "Por diseño" where the English one says "By design". It also fixes
a live defect there: the status cell asked whether the verdict was "pass"
and drew everything else as a red cross announced as "Fail", so a by-design
row was published as a failure, and the "failing rows only" filter listed it
as one. Both now know all four verdicts.
The README carries the banner under the paragraph that makes the
conformance claim, linked to the report.
Two measurements changed a decision. Starlight's own green is 1.53:1 on the
light card, so the site bar uses the marks' measured fills instead. And the
green and the red are within 1.02:1 of each other, so a failing bar reads as
a full one in greyscale; both bars now leave a sliver of track between the
segments.
* Lead every conformance row with its verdict, in words
On the documentation site the verdict was the eighth and last cell of a table
wider than the content well, drawn as a mark with the word hidden from sight,
and the box around that table never scrolled. A table whose columns cannot fit
is laid out at its min-content width anyway, but Chromium reports its border
box as the containing block's width, so the scroll container saw scrollWidth
equal to clientWidth, offered no scrollbar and clipped everything past its
right edge. Measured at 1280 px, the status cell ended 106 px outside the box
and scrollLeft stayed pinned at 0; at 360 px it ended 863 px outside. A pixel
census of untouched screenshots found exactly one verdict mark painted in the
viewport at twelve of the fourteen width and language combinations, and that
one was the mark in the section heading. Below 1440 px no data row carried a
verdict a sighted reader could reach, while the Markdown mirror printed the
word in every row.
min-width: min-content gives the container something to scroll, the verdict
moves to the first column, and its word is drawn rather than hidden. The mark
needed display: inline-block as well, because Starlight's content reset makes
every svg a block and had been placing the mark on a line above the word it
belongs to in every cell that draws one; and the column after the verdict
carries the gutter, because a nowrap verdict runs past its own cell where the
table is squeezed and padding on the overflowing cell cannot hold a gap open.
The mark stays aria-hidden, so a screen reader still hears the verdict exactly
once.
Measured afterwards at 360, 390, 768, 1024, 1280, 1366 and 1440 px in both
languages: the status cell is inside the container at all fourteen, the
container reports real overflow of 28 to 867 px and scrolls to the last
column, the page body never scrolls sideways, the verdict and its mark share a
line with at least 13 px to the citation beside them, and the marks painted in
the viewport go from one to one per visible row.
The palette's "clears 3:1 on every ground" was measured against five grounds,
four of which were not grounds. GitHub stripes even table rows, so half of the
report's rows sit on a stripe rather than a canvas, and this site overrides
Starlight's page colour, so the #17181c that three comments named is not a
ground anywhere here. Against the nine real grounds, eight clear 3:1 and
GitHub's dimmed table stripe does not: the four fills measure 2.75 to 2.82
there. They stay as they are, because no colour can do better. Clearing 3:1 on
#2d333b needs a relative luminance of at least 0.1972 while a white glyph
reading at 4.5:1 on the fill allows at most 0.1833, so the two windows do not
overlap; the glyph wins, because it is the part of the mark that is read and
every surface prints the verdict in words in the same cell. The test now
measures all nine grounds, pins the one exception, and proves the arithmetic
behind it.
What a picture pair follows was stated backwards in one direction and
correctly in the other, so both were measured across all four crossings of
desktop theme and GitHub theme. On github.com the pair follows the GitHub
theme: GitHub upgrades it into a themed-picture element that rewrites the
source's media to "not all" or to a pair of prefers-color-scheme queries.
Rendered without that JavaScript, as the /markdown API output under GitHub's
own stylesheet is, the media stays as authored and the desktop decides, so two
of the four crossings serve the wrong twin. The docstring now says both, and
says why the choice is safe either way: the banner paints its own card, whose
ink reads at 14.84:1 light and 15.91:1 dark, and which separates from a
mismatched page at 17.3:1 and 17.8:1.
The committed report drops its summary banner. That file is regenerated from
the tree it sits in and gated byte for byte, so it claims to be that tree's
report, while an image can only be cited at a fixed ref; on any branch that
adds or removes a check, a picture of main's count sat directly above a
sentence carrying the branch's. The sentence carries every number the picture
did. In its place the report gains the ten checks closest to their published
limit, which the pull-request comment and the site page have both ranked since
they were written and the published report never showed.
Two smaller corrections. The pull-request comment no longer reports a missing
test artefact as "0 tests, 0 failures (all green)". And the report's legend and
the renderer's docstring no longer say the mark sits beside its word in
Markdown: measured under GitHub's own table stylesheet, the Status column
settles at about 53.5 px of content box against the 54 px a mark plus its word
needs, so the word wraps under the mark in 563 of 566 cells at 1012 px and 493
at 1400, and a non-breaking space does not change it.
* Make the measurements in the comments the ones this tree produces
Five sentences quoted figures the tree does not give, and the branch
contradicted itself on two of them.
The scroll comment said the container reports 106 px of overflow at 1280 px.
It reports 116. The 106 is what it reported before the gutter rule sixty lines
below, which the same comment says grows the table by 10 px, so the file
disagreed with itself by exactly the amount it documented.
The byte figures were taken against a baseline that had neither the banner nor
the legend, and came out 0.6 kB high: +10.6, +58.0 and +162.8 where the
committed report gives +10.0, +57.3 and +162.2. Two other places in the same
branch already quoted the right ones.
The wrap counts came from one harness and do not survive another, which is
fair enough because the count depends on the width the harness gives the
container: 566 of 566 in one and 563 in the other. The wrapping is the
finding, so the sentence states that and stops pretending to a tally.
The line-box note said the cell is no wider. True in English and false in
Spanish, where the longer word costs 4.8 px. Both twins are peers, so the
sentence now says which is which.
And the report and the PR comment do not share two functions; they build their
markup separately and meet at asset_url, which is the one that matters,
because a path that is wrong there is wrong on both.
Take a solid's row into the elastic simulation and the detailed building model, a ground's into the outdoor models, and complete a catalogue file in your editor with its JSON Schema (#891)
* Take a solid's row into the elastic simulation and the detailed building model, a ground's into the outdoor models, and write the JSON Schema of a catalogue file
The elastic FDTD takes a solid's catalogue row wherever it takes a Material: scholte_speed and ElasticFDTD2D.from_regions read its bulk longitudinal speed, its transverse speed and its density through printed(), never its plate or bar speed, and refuse a cell the page does not print in the page's terms.
GroundSurface.medium turns a ground row into the porous half-space ground_effect, barrier_insertion_loss and atmospheric_parabolic_equation take, through the Delany and Bazley or the Miki model. A row Cox and D'Antonio mark as fitted with one model goes into that model only.
HomogeneousElement.from_solid builds the ISO 12354 element a layer of a solid's row makes, with m' = rho t and fc = c0^2 / (1.8 cL t) from the row's density and plate speed, and never picks one of the row's loss factors: the internal loss factor is the caller's to give.
io.catalogue_schema writes the JSON Schema (2020-12) of a catalogue document for the row classes it is given, and the site publishes the one of every published row class as schemas/phonometry-catalogue-1.json, held current by CI. A document may name it in a top-level $schema, which the reader takes and never reads.
* A dollar sign inside inline code opens no maths in the markdown check
The unclosed-maths rule counted every unescaped $ on a line, so the $schema key of a JSON document written as inline code in a table cell read as maths cut off by the next row. CommonMark reads a code span before any maths could open in it, so the rule now leaves code spans out of the count, and still finds maths that wraps onto a block marker, on a line with a code span or without one.
* The catalogues guide hands a solid, a ground and a wall of your own to their models, and completes a catalogue file in your editor
The guide on catalogues of your own shows a solid's row read from a data sheet going into the elastic simulation by its bulk speeds, a ground fitted to a site going into the outdoor models through medium(), with the refusal of a resistivity fitted with another model, and a block's density and plate speed building an ISO 12354 element with the internal loss factor you give. A new section writes the JSON Schema of a catalogue file with io.catalogue_schema, points a document at it with $schema, and sets an editor to the one the site publishes; the document's keys now list $schema. The elastic waves, ground effect and detailed prediction guides each take a row from a catalogue in their own terms, the published catalogues page draws its ground example through medium() and links the schema, and the Files overview and the guide indexes name it, in English, in Spanish and in the docs mirror.
* The catalogue schema describes a row class by the first line of its docstring, or by its name when it has none
* The JSON Schema writer is held to its place in io's public names
* The elastic FDTD reads a row's fields through the dataclasses module, which no local name of the module shadows
* A wetted sand of Cox Table 6.7 goes into neither outdoor ground model, as the text beside the table says
GroundSurface.medium took the eight rows of the two sands Cox and D'Antonio print at four water contents into the Delany and Bazley and the Miki models, because no footnote marks their fit. The text of Sect. 6.6.3 (PDF page 272, printed p. 215) says their parameters are those of the two-parameter model of Attenborough, so a row the text ties to that model is now refused by both, naming the page, as a row the footnotes mark with another model already was. The notes of the eight rows say so on the catalogues page, in both languages, and the docstring no longer says Cox names the fit on every row.
* The schema never marks a catalogue file the reader reads, a null in an optional key included
The reader took a null for basis, $schema and phonometry_version, and a $schema or a version of any length, all of which the schema refuses. It now refuses a null there as it does under every other key, and holds the two texts to the length of any other text. The schema holds the standards a row's own provenance names to the fields of its class, as it already held the document's. Each refused case is now checked against the place and the first words of the reader's refusal, so a case refused for another reason than its name fails; the one that was, a negative thickness written beside the same cell in another unit, now gives the negative thickness alone. A CSV file's header that names the schema is read as one that does not.
* The oracles of a solid's row in the building and elastic models cite the page each number is printed on
The detailed-model test took 600 kg/m3 for autoclaved aerated concrete from ISO 12354-1 Table B.3, which prints 400 to 800; it now reads the three materials off the Annex L element block (PDF page 84, printed p. 78), which prints the density and velocity of each, and says Annex L takes 600 from that range. The elastic test writes the modulus, Poisson ratio and density Bies Table C.1 prints for mild steel (PDF page 747, printed p. 718) as literals and holds the row's bulk and transverse speeds to their closed forms, rather than reading them back from the row under test. The elastic FDTD's docstrings say a row class is refused when it lacks any of the three cells, not only all of them.
* The catalogues guide cites ISO 12354-1 and JSON Schema 2020-12, and says why an outdoor ground raises a fit-range warning
The guide's references now carry ISO 12354-1:2017, whose Formula (B.2), Table B.3 and Annex L the wall section rests on, and the two JSON Schema 2020-12 drafts the schema is written in. After the ground example it says the call raises a PorousAbsorberWarning because an outdoor ground lies below the fit range of both models, and links to where the ground guide explains it. The catalogues page says the schema covers every row class the library publishes, not only the ones its tables use. The Spanish pages name the elastic FDTD rather than a solver object and call the bulk speed that of an extended solid, as the solids guides do.
* The catalogue schema takes the table's credit a document or a CSV header gives at its top, as one text that is not blank
* The Annex L test holds the element's constants on the left, as the rest of the file does
* The catalogue schema's patterns read as the reader does under every validator
The schema said a filled text with \S, which Python's re matches against
U+FEFF and ECMA-262 does not: a name or a credit that is only U+FEFF was read
by the reader and accepted by Python's jsonschema, and refused by an
editor's validator. The reader tells a blank text by str.strip, so the
schema moves to it: every class shorthand of a pattern the schema takes
from the reader is spelled out as the characters it matches under that
pattern's own flags, the white space str.strip strips for a filled text and
the ASCII letters and digits for a key, a column of your own and a reserved
name. Python's re and ECMA-262, with the u flag and without it, now read
each pattern alike, over every character of the basic plane.
* The catalogue schema's patterns that hold a whole text end where it ends, under Python's re and ECMA-262 alike
The seven patterns of the schema that hold a whole text were anchored with
a closing $, which Python's re and ECMA-262 read apart: jsonschema searches
with re.search, whose $ also matches before a line feed that ends the
text, so Python's validator accepted "k\n" as a row's key, "x-a\n" as a
column of your own, "mine\n" as a catalogue's name, and a day, a date or a
digest followed by a line feed, all of which the reader and an editor's
JavaScript validator refuse. Each of the seven now ends with (?![\s\S]),
which no character follows in either engine, with the u flag or without
it. The other two, the test of a text that is not blank and the reserved
form of a name, match a part of the text and are not anchored at its end,
as a test now holds. A validator built on RE2 compiles no lookahead, and so
none of the seven, which the comments and the entry now say instead of
claiming every validator. The comparison of Python and ECMA-262 covers every
pattern the schema holds, over texts that end in a line feed after a whole
key, day and digest, and the six texts are refused by both the schema and
the reader. The catalogues guide says a file the reader reads is never
marked by an editor whose validator reads regular expressions as JavaScript
or Python does, rather than by any editor.
* A catalogue is read as its reader reads the file before a byte of it is written, so nothing the reader refuses is written
write_catalogue held a document to none of the reader's limits: more than
50 000 rows, a JSON file or a CSV file past 16 MiB, a CSV header past
64 KiB, or a text longer than the reader takes (2 000 characters, 20 000
for an about or a note, from a row built in Python or an about passed in)
was written, and with overwrite=True replaced a good file with one that
read_catalogue then refused. The JSON writer now reads the text it is
about to write as parse_catalogue reads one, its UTF-8 bytes held to the
file's limit first, and the CSV writer reads the sheet and its header as
read_catalogue reads the two files, each held to its own limit first, so
whatever the reader refuses, for its size, its rows, the length of a text
or anything else, is refused before anything is written or replaced, in
the reader's own words and naming the file. The reader looks its size
limits up when it runs, and the CSV reader reads the bytes of the two files
through one function the writer shares. The calibration sidecar writer
already refused a sidecar past the 1 MiB its reader takes, before it
touched the file.
For each writer, a file of exactly the most rows, the most bytes of the
file and of a CSV header, and the longest text and prose the reader takes
is written and read back, and one more row, one more byte or one more
character is refused over it, the good file left byte for byte and nothing
beside it; the limits of rows and bytes are lowered for the test. Each of
the nine fails on the code before this change.
* A code span in the markdown check closes only on a run of backticks as long as its opener, and the size refusals share the name of a catalogue file
CommonMark closes a code span only on a whole run of backticks of the opener's length. The check took one tick of a longer run as the closer, so a dollar sign after an unmatched backtick was read as code and an unclosed maths delimiter went unreported; each run is now read whole. The three size refusals name the file with one constant.
A flag is written by name everywhere, and the clip gate learns which changes cannot move a frame (#760)
#759 closed the flags a caller could reach. This closes the rest, so ruff's
FBT family is selected outright instead of documented as absent: 202
signatures take the star, and the 296 calls that passed a bare True name the
parameter.
Every one of the 156 call sites the change forced was named rather than left
positional. Two of them no static gate sees: _cached_weighting_sos and
_cached_weighting_filter are lru_cache'd, so mypy reads the call through
_lru_cache_wrapper and checks nothing, and only the suite found them.
The one place a keyword-only parameter is not a rewrite: Callable[[...], R]
cannot say that a parameter is keyword-only. ColumnsBuilder in
_report/_insulation_fiche.py and a new LeftCellBuilder in
_report/ansi_s12_2.py become protocols, which say what the alias could not.
FBT003 came down to ax.grid(True, alpha=0.3) in 295 of its 296 sites.
matplotlib declares that parameter visible, so the sites say visible=True and
a test pins the name, because a matplotlib release that moved it would
otherwise surface as a wall of unrelated red. The one that was left is
np.bool_(True) in a test, a cast rather than a flag; it is np.True_ now.
The clips are not re-rendered, and none of them needed to be.
animation_fingerprint already normalises away what cannot move a frame, the
docstrings, the import order, the TYPE_CHECKING blocks, with the reason on
each. Where the keyword-only star sits is the same kind of thing: it decides
how a caller may write the call, not what the function computes. With that
normalisation the 43 fingerprints are identical either side of the signature
sweep, measured, not assumed. The manifest is re-stamped because the
fingerprint itself changed, and the stamp records the same clips it always
described.
scripts/check_public_flags.py goes: ruff now says the same thing on every
definition, and a guard that cannot fire is noise.
Predict in a named air, not in two floats standing side by side (#692)
The rule the visco-thermal models adopted reaches `building` and `simulation`: a
function needing two or more properties of the medium takes a `Fluid`, and one
needing only a speed of sound keeps the scalar.
Nine `building` entry points move, from `mass_law_transmission_loss` to
`in_situ_element`, and `simulation.far_field_from_contour` with them. Each took a
speed of sound and a density side by side and re-checked both; the invariant
belongs to the type that owns them, which refuses a non-positive property on
construction, so the refusal happens a step earlier and covers every property
rather than the one each function remembered to check.
`helmholtz_resonance_frequency` keeps its scalar, because a resonance of a neck
and a cavity needs only the speed of sound.
Each domain publishes the air it is written around instead of repeating the
numbers. `building.EN_12354_AIR` is the 340 m/s of EN/ISO 12354 Annex A with the
1,29 kg/m3 of Annex B, transcribed rather than recomputed, because a standard's
own constants belong with the clause that prints them.
`simulation.SIMULATION_AIR` is the `AIR` material the solvers run in, written as
a fluid, so the near-to-far-field transform and the simulation it reads from
agree. Neither is the 343,0 m/s and 1,205 kg/m3 of the absorber models, and that
is the point: three populations of air that were three pairs of loose floats are
three named fluids.
A plate immersed in water is what showed the argument was never "the air". Two
elastic-solver tests hand `mass_law_transmission_loss` the water they integrate,
under a parameter that said `air_density`; they build a water `Fluid` now and say
so.
`panel_transmission` had also been carrying a `_GAMMA` and an `_AIR_DENSITY` that
nothing read, the second of them left dead by this change; its remaining private
speed of sound reads the published air rather than spelling 343 m/s again.
Nothing moved numerically: 623 of 623 conformance checks reproduce to the digit,
and the two Heckl rows that need Bies's rho c = 414 build that air explicitly
rather than passing a density alone.
The unit of critical_angle depended on which function you called (#757)
* The unit of critical_angle depended on which function you called
#755 closed the bare names of the geometry. These are the compounds built
on the same words, and one of them is worse than anything the first pass
found: in weston_regimes.py, WestonRegimeBoundaries.critical_angle is in
radians and weston_regime_boundaries(critical_angle=...) one screen below
it takes degrees, while seabed_reflection.py has it in degrees again. The
same name, 57 times apart. The field is critical_angle_rad now and the two
overrides critical_angle_deg, which is what the function converts to
anyway.
The rest, read off each docstring: degrees for bank_angle, path_angle(s),
grazing_angle, launch_angles, arrival_angles, source_angle and
limiting_angle; radians for incidence_angle and angle_limit; metres for
the thirteen diameters; steradians for solid_angle; per second for
sound_speed_gradient; nepers per radian for reflection_loss_gradient and
its override. runway_gradient becomes runway_gradient_ratio, because its
own docstring says dimensionless.
Two public functions were caught by the sweep and put back:
critical_angle(c1, c2) and reflection_loss_gradient(seabed). The rule is
about parameters; what a function returns is said by its return type.
element_diameter and pitch_diameter stay bare in the guard's exemptions,
because the bearing formulae use them only as the ratio d/D.
The guard matches the geometric quantities as whole words inside a name
now, so critical_angle and duct_diameter are held to the rule and
triangles is not, and the two tuples of the first pass collapse into one.
No value changes: the same 995 conformance checks with the same numbers.
One clip is re-rendered, because its scene reaches the renamed parameters.
* The geometric conditions with a default are written by name too
The rule of #756 now reaches the names #755 and this branch renamed.
Thirteen more conditions carry a default and could still be passed as a
bare number.
piston_directivity_pattern and hydrophone_depths take a star before
their angle argument, which keeps the quantity the call is about
positional.
Nine result dataclasses take KW_ONLY after the fields they are about,
among them ApproachStep and DepartureStep, whose ANP steps were being
written as five numbers in a row against a column of sheet C-6.2.
* Say both halves of the rule in the guard's own docstring
Search a catalogue of your own with every lookup by name, draw a panel's plateau from its row, and a guide to keeping catalogues of your own (#888)
* Search a catalogue of your own with every lookup by name, and draw a panel's plateau from its row
Every *_named lookup of a published catalogue takes catalogue=, the rows to
search in place of its own PUBLISHED_*: a catalogue read from a file, the
published one joined with it by |, or any mapping of key to row. Each keeps
its own way of matching a name, answers every match in the order the mapping
holds them and never picks one, and refuses a row of another class by its
key. The join of two mappings of one row class is typed as a mapping of that
class. building.plateau_transmission_loss takes a solids.PlateauMaterial row
as its material and reads its three numbers through printed(), so a bound is
refused in the sheet's own words, and a number passed explicitly replaces the
row's without reading it.
* A guide to keeping catalogues of your own, and the published catalogues page says where they go
"Your own catalogues" (EN and ES, with its docs/ twin) takes a data sheet
from a published table written out as a template to the rows in the models:
the document and its provenance, the refusals that point at a cell, a porous
core in the transfer-matrix model, a spectrum in a reverberation time, a
board in the plateau method, a floating floor's s' and s't, and every lookup
searching yours and the published ones at once. It shows how to write a
bound, a word, a range and a figure in another unit, lists the units a cell
takes, says which row class holds which quantity, and what the library never
does with the data. The guide is registered in the Files topic and the guides
index (145), and the published catalogues page gains a section on why it
never shows a manufacturer's table and where your own go.
* A refused catalogue row or plateau material is named by its class in words that read right for every class
A lookup given a catalogue that holds a row of another class now says
"holds a row of class AbsorptionSpectrum under 'mine/one'", and one given
something that is not a mapping, or a plateau material that is neither a name
nor a PlateauMaterial, ends with "got list" the way the other type refusals
of the library do, instead of putting "a" before a class name that needs
"an". The three lookups whose row class starts with a vowel say so in their
docstrings too.
* The contributing guide sends a manufacturer's data to the guide on catalogues of your own
The paragraph that says a data sheet, a declaration of performance or a test
report is never merged now links "Your own catalogues", which shows how to
keep such data in a file of your own and read it into the same rows.
* Every lookup by name finds a name however its accented letters are stored
A name pasted from a document can store an accented letter as the plain
letter followed by a combining accent. It prints the same as the one typed,
and a lookup that only folded case answered it with nothing. The twenty
lookups now compare the name asked for and each row's text in one Unicode
form, through one shared function, so both forms find the same rows.
Their summaries and return lines describe the catalogue searched, not only
the published one, and the curated API table says the same. The plateau
tests cover an explicit mass per area and frequency ratio beside a row as
well as the height, the lookup guard holds every public *_named to the shape
of a lookup instead of skipping one annotated otherwise, and the type check
covers a new tests/static_typing directory, where a published catalogue
joined with yours is checked to be accepted by a lookup's catalogue=.
* The catalogues guide says what a laboratory's R is, which kinds a provenance takes and what a row's source cites
The guide on catalogues of your own no longer calls every
TransmissionLossSpectrum row a field-incidence value or says a laboratory's
R comes with its own flanking: ISO 10140-2 measures R in one-third-octave
bands on one specimen, where flanking has been shown to be negligible, and
rates it with ISO 717-1, while a book compiles octave bands from tests it
seldom names. The document table names the seven provenance kinds, the date
format and phonometry_version; the source is said to leave the test date and
the standards in the provenance; a temperature in a row class of your own
takes only its own unit; the floating-floor example states s't to the whole
MN/m3 a test report prints; and the template is the one foam of Allard &
Atalla's Table 13.1. The Spanish page says módulo de cizalla, as the rest of
the site does.
* A plateau panel reads its material and the constants it gives in two steps of their own
The name or row is held to what it may be, and each number the caller leaves
out is then taken from the material, as before.
* A lookup searches the very rows it held to their class, the mapping read once
A lookup given catalogue= held every row to its class over the mapping's
items and then read the rows again from its values, so a mapping that
changed between the two readings could hand the lookup a row of another
class without the TypeError it documents. The rows held to the class are
now the rows searched, in the order the mapping gave them. A test with a
mapping whose values are not the rows its items give fails on the code
before this change, for each of the twenty lookups.
A flag is written by name everywhere, and the clip gate learns which changes cannot move a frame (#760)
#759 closed the flags a caller could reach. This closes the rest, so ruff's
FBT family is selected outright instead of documented as absent: 202
signatures take the star, and the 296 calls that passed a bare True name the
parameter.
Every one of the 156 call sites the change forced was named rather than left
positional. Two of them no static gate sees: _cached_weighting_sos and
_cached_weighting_filter are lru_cache'd, so mypy reads the call through
_lru_cache_wrapper and checks nothing, and only the suite found them.
The one place a keyword-only parameter is not a rewrite: Callable[[...], R]
cannot say that a parameter is keyword-only. ColumnsBuilder in
_report/_insulation_fiche.py and a new LeftCellBuilder in
_report/ansi_s12_2.py become protocols, which say what the alias could not.
FBT003 came down to ax.grid(True, alpha=0.3) in 295 of its 296 sites.
matplotlib declares that parameter visible, so the sites say visible=True and
a test pins the name, because a matplotlib release that moved it would
otherwise surface as a wall of unrelated red. The one that was left is
np.bool_(True) in a test, a cast rather than a flag; it is np.True_ now.
The clips are not re-rendered, and none of them needed to be.
animation_fingerprint already normalises away what cannot move a frame, the
docstrings, the import order, the TYPE_CHECKING blocks, with the reason on
each. Where the keyword-only star sits is the same kind of thing: it decides
how a caller may write the call, not what the function computes. With that
normalisation the 43 fingerprints are identical either side of the signature
sweep, measured, not assumed. The manifest is re-stamped because the
fingerprint itself changed, and the stamp records the same clips it always
described.
scripts/check_public_flags.py goes: ruff now says the same thing on every
definition, and a guard that cannot fire is noise.