Commit Graph

27 Commits

Author SHA1 Message Date
dev 73b5f3de63 Wrap a long identifier, and add the rendered page to the audit
A doc comment names an item by its full path, as in
`NoiseTemperature::from_noise_figure_db`. A path has no space in it, so
the column could shrink and the word could not, and the interface page of
a crate scrolled sideways on a phone. The body of a document now breaks a
word rather than overflow.

The audit that renders every route now covers the whole interface: 744
combinations, being ninety-three routes in both languages and both themes
at two widths, and it passes. It reports four things, which are the four
ways a page has failed here before: a page that does not load, a page
with almost no text, a page that scrolls sideways, and a formula that
loses a letter or a digit.

Two mistakes of the audit itself are fixed rather than worked around.

It awaited a `Runtime.evaluate` that called `location.reload`. Such a
call destroys its own execution context, so the reply never arrives, the
promise never settles and the run hangs until the environment kills it.
The preferences are now set once per language on a page that stays put,
and each route is reached by an ordinary navigation.

It gave the browser a function whose comment contained a backtick. The
backtick closed the template literal that held the function, so the script
did not parse at all.

The formula comparison now treats a command name as notation, as it
already did for the operators: \Delta draws a Greek letter and \sqrt a
radical sign, so neither is drawn as the letters of its own name.
2026-10-02 11:22:02 +08:00
dev 4957368aa3 Give every piece of a formula an element, and check the page for it
A formula is written as plain text and translated to MathML. Text left
bare inside a row is not drawn by the browser, so a token without an
element disappears: every multi-digit number did. `a = floor((14 - month)
/ 12)` came out as `a = floor ( ( - month ) )`, and `year + 4800` as
`year + `. The markup looked reasonable at a glance, and the numbers were
simply gone.

The classification now covers every kind of text and has no bare output.
A number of any length is `mn`; one letter of any script is an identifier,
so Greek stays a variable rather than becoming upright text; an operator,
including one written with its spacing, is `mo`; a space is an explicit
`mspace`; and anything else is `mtext` rather than nothing.

A test walks every document in both languages and compares the characters
the page would show against the characters the formula was written with.
It found three more formulas dropping a sign, and it now guards the whole
set: ninety-six formula blocks, checked on every run rather than by
looking at a page. Only letters and digits are compared, because the
other characters in a formula source are notation — `^`, `_`, `*`,
`/`, braces, and the word `sqrt`, which is drawn as a radical sign.
2026-10-02 10:42:51 +08:00
dev 196727c778 Take the interface translation from the apsis-rs doc comments
`apsis-rs` now writes each doc comment in English and then in Chinese, in
the one comment beside the code. The extractor splits the two halves as it
reads them and writes both to the catalogue, so the interface
documentation carries both languages and no translation file is maintained
beside it.

This replaces `content/api.zh.json`, which held the Chinese keyed by item
name. That arrangement was unsound: a name is not unique. `new` is
defined by fifty-nine crates and does not mean the same thing in each, so
a translation filed under the bare name could be shown against the wrong
documentation. Splitting the comment removes the question, because the
translation is attached to the item rather than looked up by a name.

The coverage went from 434 of 1202 items to all of them, and the crate
summaries from 15 of 40 to all of them. A test now asserts that no item in
the committed catalogue is left without Chinese, so a crate that is not
translated fails the build rather than reading as English to a Chinese
reader.

Two defects surfaced while doing this.

The JSON codec decoded one string character by validating the whole
remaining buffer as UTF-8. That is correct and quadratic, and it repeated
for every character of the document: the catalogue took twenty-nine
seconds to parse once it grew, and the service could not start. It now
validates only the sequence at hand, which is six milliseconds.

The module documentation was joined into one line before it was split,
which destroyed both the paragraph structure and the boundary between the
languages, so the English half came out empty and the Chinese half held
the English text.
2026-10-02 09:47:02 +08:00
dev ff69c1cd63 Move every test out of src, as apsis-rs does
The service is a library with a thin binary over it, which is what makes
the move possible: an integration test is a separate crate and reaches
only what the library makes public, so the modules now live in
`src/lib.rs` and `main.rs` is the entry point. `src/` holds no test
code, which is the shape `apsis-rs` already has.

Eleven items are internal to a module and a test reaches them anyway.
Those stay `pub(crate)` where they are defined and are offered through
`src/testkit.rs`, which is the one place a caller is expected to look for
them. A wrapper is also the only way to offer a private thing outward:
Rust does not let visibility be widened twice, so a `pub(crate)` item
cannot be re-exported as `pub`. That keeps the seams in one file instead
of scattering them through the modules under test.

The 146 module tests and the 23 end to end tests all still run, which is
the number this move had to preserve: the 146 are spread over eighteen
files in `tests/`, one per module that had them.
2026-10-02 01:56:21 +08:00
dev ed2b779d7b Reformat after the rename
`APSIS_BOOK` is one character longer than `APSIS_WEB`, which pushes a
few lines past the width rustfmt allows.
2026-10-02 01:29:36 +08:00
dev cd2f4de8ba Rename the service to apsis-book
The service was named for what it is: a web service. It also serves the
concept documentation as a book, which is the larger part of what a
reader comes for, and the name is shorter without losing what the
service does.

The crate, the binary, the environment variables, the storage keys, the
help text, the documentation, and the history all carry the new name.
2026-10-02 01:24:42 +08:00
dev 0a8f00a8fa web: license as GPL alone, and give every document a Chinese form
The service was offered under MIT or Apache-2.0. It is now under the
GNU General Public License, version 3 or later, and that alone: the two
other licence files are removed and the manifest names one licence.
`apsis-rs` is still MIT or Apache-2.0; both permit redistribution
inside a GPL work, so the two may be distributed together under these
terms.

Every document now has a Chinese form. The concept set already had one
for each of its thirty-one documents; the README and the design notes
did not, and both now do.

The design notes carried two sections under the same heading and two
under another, so the second copy of each was unreachable from the
outline. They are merged into one section apiece, keeping every distinct
decision and dropping the two lead-ins that said the same thing twice.
2026-10-02 00:55:00 +08:00
dev 7d2cf4ba73 web: fix four defects the audit found
A bracketed group was never given its power, so `(1 - e^2)^2` and every
line of that shape were shown as source. An operator written with its
spacing was emitted as bare text, and a browser drops bare text inside a
row, which lost the sign of a difference: `1 - e^2` came out as `1e^2`.
A parenthesis holding words was read as a note about the equation rather
than as part of it, so `(cos theta)` and `(m * g)` broke the lines that
held them; the parser now decides, and the column a note is set in is
what marks it. A vertical bar ended an absolute value only from the
outside, so `| f'(x) | * | x| / | f(x) |` did not read.

A grid track of `minmax(28rem, 1fr)` is wider than a phone, so the
interface page of a crate scrolled sideways. The track now takes
`min(28rem, 100%)` and shrinks to the width it has.

The equations of the documents went from seventy being set as formulas
to ninety-six. What is left is pseudocode and matrices, which are source
rather than formulas.
2026-10-02 00:35:10 +08:00
dev c61f453d9e web: key a translation by its crate, and drop the facade from the catalog
A translation was filed under the item name alone. The name is not
unique: `new` is used by fifty-nine crates and `kind` by fifteen, and
they do not all mean the same thing by it, so a name-only translation
could be shown against the wrong documentation. A translation is now
looked up by `crate::name` first, then by `Type::name` for two items
of one crate that share a name, and only then by the bare name.

The facade crate sits directly in `crates` and re-exports every layer.
It defines nothing of its own, so listing it repeated every item of the
layers under a second name. The generator skips it and the catalog
carries forty crates.

The first batch of Chinese translations is in, covering the foundation,
time, coordinate, geodesy, frames, Kepler, SGP4 and linear algebra
crates.
2026-10-01 23:44:55 +08:00
dev 63c77aff69 web: read the formulas the documents already write, and take the crates from the manifest
The documents write their formulas as plain text in a fenced block,
`delta_v = v_e * ln (m_0 / m_f)`, which was shown as source. They were
written before the dollar form existed. A plain block holding equations
is now read as a formula: identifiers with subscripts and powers, roots,
functions, quotients, a group raised to a power, and a note set beside
the equation. A block that is not an equation, such as a matrix or a
worked example in prose, stays as it was written.

The interface catalog named fifteen crates in the generator, which was
written when only the foundation, physics and orbit crates existed. The
workspace has since grown to forty-one, and every network, radio and
operations crate was missing from the documentation without anything
saying so. The crates now come from the workspace manifest, so a crate
cannot be left out by omission again. The count went from 424 items to
1202, and the index now shows all seven layers.

A crate with no layer is the facade, which re-exports every layer. It is
left without one rather than filed under the foundation, and it is left
out of the crate structure diagram, where it would belong to no layer.
2026-10-01 23:24:56 +08:00
dev 50d6ecc9fd web: scroll to the top on navigation, organize the interface by layer, and set the formulas in the tool output
A page change did not move the scroll position, so following a link from
the bottom of a long document landed in the middle of the next one. The
scroll now follows the path rather than the fragment, so a filter applied
to the page a reader is on leaves them where they are. The browser fires
`popstate` for a fragment navigation as well as for a traversal, so
there is no event that means "this was a traversal" on its own, and going
back starts at the top rather than where the reader left.

The interface index listed fifteen crates in one grid. It is now grouped
by layer, with the title and order the concept documentation already
declares, and a card shows the opening sentence of the crate summary
rather than the whole of it, which is what made the cards four hundred
pixels tall.

A tool result showed its column headings, scalar labels and notes in the
reader's language, but left the table body in English. Text cells are now
looked up as well. Units are written with a power, and are set as one.

A tool description is Markdown, so it is now rendered as such, as are the
parameter help and the notes. A formula written between dollar signs is
set the same way in both places.
2026-10-01 22:46:56 +08:00
dev 17e99428de web: split the physics layer, render formulas, and fix the graph load
The graph took over three seconds to draw. The force layout ran four
hundred and twenty steps of repulsion between every pair of nodes, which
is quadratic in the node count and was doing that work through a reactive
proxy inside an effect that read the state it wrote, so it rescheduled
itself on every run. The repulsion now runs on a grid over neighbouring
cells, and the effect no longer tracks its own writes.

The physics layer covered two unrelated subjects, so it is presented as
two. Formulas are written between dollar signs and translated to MathML,
which the browser sets itself, so no script has to run. The palette is
now two sets of the same variables with a toggle between them, and below
a thousand pixels the sidebar is a drawer over the page.
2026-10-01 17:28:43 +08:00
dev 68eaaf6b20 web: restore the layout variables, align the sidebar rows, and name the layers 2026-10-01 15:55:19 +08:00
dev c726dd1ecc web: describe the field by layer and separate it from the implementation 2026-10-01 13:57:23 +08:00
dev 3a3caf5496 web: give a tool its own page instead of sharing the index 2026-10-01 11:31:26 +08:00
dev b4ed846f73 web: fix the outline anchors, level the outline, and fold the sidebar chapters 2026-10-01 11:00:09 +08:00
dev bc662bc492 web: cancel the sibling margin inside a card grid 2026-10-01 10:28:20 +08:00
dev 829825ac73 web: give every card on a page one size 2026-10-01 09:38:16 +08:00
dev 87dd6b78d0 web: name assets with a content hash so a stale bundle cannot be served 2026-10-01 09:06:10 +08:00
dev 839162dc3e web: align the interface layout and translate the remaining captions 2026-10-01 08:46:46 +08:00
dev 3d716469d1 web: correct the asset cache policy, serve the flow index, and drop a stray artifact 2026-10-01 07:35:56 +08:00
dev 65b0b690f7 web: fix the tool form, the search box, the toc anchors, and translate the interface 2026-09-27 10:29:10 +08:00
dev b4c9627cbb web: fix the interface layout and add Chinese search 2026-09-27 09:45:26 +08:00
dev b7e5222bcd web: add a bilingual interface with Chinese as the default 2026-09-27 09:13:52 +08:00
dev 0415a5fe6f web: bind with --host and --port 2026-09-27 09:13:47 +08:00
dev 25f9b28e9e web: register the hohmann transfer tool and check graph references 2026-09-27 00:54:28 +08:00
dev 2a14c59264 web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00