viafrei 1.3.12 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +623 -0
- package/CHANGELOG.md +684 -0
- package/LICENSE +2 -1
- package/NOTICE +23 -7
- package/README.md +207 -48
- package/SOURCES.md +332 -87
- package/dist/config.d.ts +10 -0
- package/dist/config.js +39 -6
- package/dist/failure.d.ts +10 -1
- package/dist/failure.js +51 -3
- package/dist/fetch.d.ts +19 -0
- package/dist/fetch.js +77 -4
- package/package.json +20 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,688 @@
|
|
|
3
3
|
All notable changes to this package are documented here. The format follows Keep
|
|
4
4
|
a Changelog and the versions follow Semantic Versioning.
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
Nothing yet.
|
|
9
|
+
|
|
10
|
+
## [1.3.16] - 2026-09-27
|
|
11
|
+
|
|
12
|
+
**This is the release that delivers the licence corrections to the people the
|
|
13
|
+
licences point at.** `NOTICE` is the file Apache-2.0 § 4(d) makes every downstream
|
|
14
|
+
redistributor carry, and until this publish the corrected text existed only in the
|
|
15
|
+
repository: the 1.3.15 tarball on the registry still carries the previous wording. So
|
|
16
|
+
publishing is not a side effect of the correction, it **is** the correction — which
|
|
17
|
+
is the whole reason this release exists, because nothing in `dist/` changes.
|
|
18
|
+
|
|
19
|
+
The number matches the running service rather than counting the changes here.
|
|
20
|
+
Production answered `initialize` with `1.3.16` when it was asked on 2026-09-27, and
|
|
21
|
+
this package is the bridge to that server, so somebody comparing the two now reads
|
|
22
|
+
one number instead of wondering which is behind.
|
|
23
|
+
|
|
24
|
+
**No behaviour changes.** `dist/` is built rather than committed, and no file under
|
|
25
|
+
`src/` has changed since the 1.3.15 tag — which is the evidence for the claim, since
|
|
26
|
+
a diff of an untracked directory would be no evidence at all. So no flag, default or
|
|
27
|
+
exit code moves. **Six** of the seven `files` entries do change —
|
|
28
|
+
`README.md`, `LICENSE`, `NOTICE`, `SOURCES.md`, `CHANGELOG.md` and the new
|
|
29
|
+
`API.md` — and the tarball goes from twenty paths to twenty-one. (Six *entries*,
|
|
30
|
+
not six files: `dist` is a directory.)
|
|
31
|
+
|
|
32
|
+
This paragraph has now been wrong twice, which is worth leaving on the record
|
|
33
|
+
rather than tidying away. The first draft called these "the repository's own
|
|
34
|
+
development scripts" and said the next tarball would differ in two files — true of
|
|
35
|
+
the first change here, false once the licence work landed beside it. The second
|
|
36
|
+
draft said **four** files and omitted `LICENSE` — and the commit that wrote that
|
|
37
|
+
sentence is the same commit that changed `LICENSE`, so it was false at the moment
|
|
38
|
+
it was written, in the paragraph written to correct a false count. The count moved
|
|
39
|
+
once more at the cut, because `API.md` joined `files` in this release. Every
|
|
40
|
+
version of it has been computed from `package.json`'s `files` intersected with
|
|
41
|
+
`git diff --name-only v1.3.15..HEAD`, with the path count from `npm pack --json`,
|
|
42
|
+
rather than counted by eye — which is the only way this sentence has ever been
|
|
43
|
+
right.
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **A sweep that keeps the twenty-first call site from being written by accident**
|
|
48
|
+
(`scripts/tools.test.mjs`, `npm run test:tools`, and a step in CI). Eighteen
|
|
49
|
+
cases: what `resolveTool` accepts and refuses, that its directory list is
|
|
50
|
+
root-owned and not group- or other-writable (the property the module relies on,
|
|
51
|
+
rather than the list that is supposed to have it), that its contents cannot be
|
|
52
|
+
extended at runtime, that an `npm_execpath` which is absolute, real and readable
|
|
53
|
+
but not npm is refused, and then a sweep of all thirty-two source files,
|
|
54
|
+
walked recursively, for a spawn whose program is a bare quoted name.
|
|
55
|
+
|
|
56
|
+
It carries three preconditions, because a gate whose input is absent reports
|
|
57
|
+
success about what it never read: **every** source root must have contributed a
|
|
58
|
+
file and an unreadable root is a failure rather than an absence; the expression
|
|
59
|
+
must locate a program argument in a real file of this repository, proved by
|
|
60
|
+
putting a real call's program back to a literal in memory and requiring it to be
|
|
61
|
+
found; and it must go red on a planted bad call, with the fixtures assembled at
|
|
62
|
+
runtime so no literal in this file can satisfy its own sweep.
|
|
63
|
+
|
|
64
|
+
Both of the last two exist because the first drafts did not do what their own
|
|
65
|
+
comments claimed. The floor was a floor on the *sum*, and `scripts` and `test`
|
|
66
|
+
clear it between them — so `src/` could be deleted entirely and the run still
|
|
67
|
+
printed ok at 21 files. And the "it can see a call" precondition evaluated the
|
|
68
|
+
real expression only on the negative case; the positive half used a different,
|
|
69
|
+
simpler pattern and never asked the real one to read a file.
|
|
70
|
+
|
|
71
|
+
Proved the way a gate has to be: one real call site reverted to a bare name
|
|
72
|
+
turns the sweep red, one source root removed turns precondition 1 red, and the
|
|
73
|
+
files were restored byte-identical afterwards.
|
|
74
|
+
|
|
75
|
+
- **[API.md](API.md): a reference for all 18 tools, generated rather than written.**
|
|
76
|
+
`catalogue.json` is what the production server answered when it was asked to
|
|
77
|
+
describe itself — `initialize` plus `tools/list`, `resources/list`,
|
|
78
|
+
`resources/templates/list` and `prompts/list`, captured on 2026-09-27 from
|
|
79
|
+
server `1.3.16`. `scripts/gen-api-doc.mjs` renders the document from it
|
|
80
|
+
(`npm run docs:api`), and `npm run check:docs` in CI fails if the two have
|
|
81
|
+
drifted. Every tool description in it is the server's own text, verbatim,
|
|
82
|
+
because that text is what an assistant reads when it decides which tool to
|
|
83
|
+
call — paraphrasing it would document a different server.
|
|
84
|
+
|
|
85
|
+
**No tool was invoked to produce the snapshot.** Listing is metadata; calling is
|
|
86
|
+
traffic, and one of the providers behind this service sets a floor on how often a
|
|
87
|
+
station may be queried, with the access itself at risk if it is exceeded. The
|
|
88
|
+
capture is therefore five list methods and nothing else.
|
|
89
|
+
|
|
90
|
+
**What generating it does and does not fix**, because README.md already argued
|
|
91
|
+
the opposite case and that argument was right. Drift between the document and the
|
|
92
|
+
snapshot is now impossible to keep — CI regenerates and compares. Drift between
|
|
93
|
+
the snapshot and the live server is not fixed by anything, because a capture is a
|
|
94
|
+
point in time. So API.md's own header says it is a dated snapshot, carries the
|
|
95
|
+
date, and names the running server as the source of truth — in that file and not
|
|
96
|
+
only in README.md. Both of them ship in the tarball, so that is not the reason;
|
|
97
|
+
the reason is that a qualification has to travel with the document it qualifies,
|
|
98
|
+
because somebody who opens the catalogue to look up a parameter has no occasion
|
|
99
|
+
to read the page beside it.
|
|
100
|
+
|
|
101
|
+
Two substitutions in the snapshot, both recorded in its own `$comment` rather
|
|
102
|
+
than left as silent differences from what the server sent: the 18 per-tool
|
|
103
|
+
`$schema` declarations are dropped as one constant repeated 18 times, and two
|
|
104
|
+
288-character date patterns are stored as their LENGTH. The second was forced by
|
|
105
|
+
the leak sweep and the interesting part is which side gave way — such a regex
|
|
106
|
+
spells its arithmetic as character classes of selected digits, which a digit-run
|
|
107
|
+
scanner cannot tell from a five-digit internal value. Both remedies on the
|
|
108
|
+
sweep's side would have been falsehoods: narrowing the scanner weakens it for
|
|
109
|
+
every file, and an allow-list entry would record that a character class is a
|
|
110
|
+
number this project publishes. So the text that cannot be scanned is not stored.
|
|
111
|
+
Nothing is hidden by it — the document already summarised a pattern over 60
|
|
112
|
+
characters by its length, and the server hands anyone the full expression.
|
|
113
|
+
|
|
114
|
+
One parameter is an object whose seven keys each carry their own bounds, and the
|
|
115
|
+
first draft rendered it as a dash in both the default and the constraints
|
|
116
|
+
column — the table's strongest claim broken on the row with the most to say. The
|
|
117
|
+
cause defeated the safety net as well: `properties` sat in the set of keywords
|
|
118
|
+
the renderer treats as handled, so the fallback that lists an unrecognised
|
|
119
|
+
keyword as a bare name never fired. The keyword was known; it was simply never
|
|
120
|
+
rendered.
|
|
121
|
+
|
|
122
|
+
- **A self-test for the API-reference generator** (`scripts/gen-api-doc.test.mjs`,
|
|
123
|
+
`npm run test:docs`, and a step in CI). Its cases include the drift check refusing a
|
|
124
|
+
hand-edited file, never writing during `--check`, and naming `docs:api` when the
|
|
125
|
+
document is absent; eight snapshot mutations each refused with a named reason; a
|
|
126
|
+
malformed `required` rendering rather than throwing; a planted nested `default`
|
|
127
|
+
reaching the document; a union type in a table cell and in a bullet; an
|
|
128
|
+
array-of-scalar; and the reported line count agreeing with `wc -l`. The run prints
|
|
129
|
+
the total, which is the number to trust — this file has been wrong about counts
|
|
130
|
+
more than once, so it states none here.
|
|
131
|
+
|
|
132
|
+
It exists because the generator was the only script here making claims with nothing
|
|
133
|
+
checking them, and the same six mutants were being re-run by hand across three
|
|
134
|
+
review rounds — a check performed by remembering is not a check. It also earned
|
|
135
|
+
itself immediately, by catching two defects nothing else could:
|
|
136
|
+
|
|
137
|
+
The whitespace-flattening expression, rewritten to remove a super-linear
|
|
138
|
+
backtracking pattern, **was not equivalent to what it replaced.** It handled only
|
|
139
|
+
spaces and tabs beside the newline, so a `\r\n` line ending would have left a stray
|
|
140
|
+
carriage return in the document. API.md regenerated byte-identical, `--check`
|
|
141
|
+
passed, every gate was green — because this snapshot contains no CRLF. An output
|
|
142
|
+
comparison can only speak about the input it was given, so the test compares the two
|
|
143
|
+
**expressions** over every string up to length four drawn from a whitespace-heavy
|
|
144
|
+
alphabet, plus random longer ones, and asserts first that the alphabet can expose
|
|
145
|
+
the bug that shipped.
|
|
146
|
+
|
|
147
|
+
And a **union type was escaped twice**: `typeOf` joined with an already-escaped pipe
|
|
148
|
+
and the cell renderer escaped that pipe again, giving `string \\| null` — a literal
|
|
149
|
+
backslash, and a bare pipe left to end the table row early. In a bullet, which is not
|
|
150
|
+
a table, it produced a stray backslash instead. No tool in this snapshot declares a
|
|
151
|
+
union type, so neither was reachable and no comparison of documents could have found
|
|
152
|
+
it. Escaping now happens in one place, the one that knows it is writing a table cell.
|
|
153
|
+
|
|
154
|
+
- **[SUPPORT.md](SUPPORT.md)**, so GitHub's issue chooser has somewhere to point:
|
|
155
|
+
where a question, a wrong answer and a security report each go, and what makes a
|
|
156
|
+
report actionable.
|
|
157
|
+
|
|
158
|
+
- **README gains a Documentation table and five worked use cases** — a motorway
|
|
159
|
+
briefing, a broken commute including a station lift that is out, an EV weekend, a
|
|
160
|
+
dispatcher's morning brief, and a local-guide agent — each named by the question
|
|
161
|
+
it answers rather than by the tools it calls.
|
|
162
|
+
|
|
163
|
+
### Changed
|
|
164
|
+
|
|
165
|
+
- **One entry of 13 characters left the leak sweep's private-name list, under that
|
|
166
|
+
list's own rule 1.** The rule is stated in `scripts/rules.json`: an entry must not
|
|
167
|
+
be a substring of text this repository legitimately prints, because such an entry
|
|
168
|
+
can never be satisfied, and the only ways out are deleting it or narrowing the
|
|
169
|
+
scanner — which is strictly worse. There is no mechanical test for it; the sweep
|
|
170
|
+
going red *is* the test, and it went red. Declared narrowing: one spelling of 13
|
|
171
|
+
characters is no longer matched anywhere. The list's second rule is not engaged,
|
|
172
|
+
which decides that nothing else follows: the audit recorded in that file says
|
|
173
|
+
nothing on the list is from the class whose harm is confirming a guess —
|
|
174
|
+
credentials, tokens, session or contract identifiers, access-granting hostnames,
|
|
175
|
+
personal data — so there is no rotation and no rename here.
|
|
176
|
+
|
|
177
|
+
Recorded that way on purpose, and it is a change of practice rather than of
|
|
178
|
+
style. The two removals recorded under 0.0.9 described what the entries were
|
|
179
|
+
ABOUT, and taken together those descriptions narrowed the candidate space for a
|
|
180
|
+
live entry further than a hash does — the same caption failure the number
|
|
181
|
+
allow-list refuses on the facing page. The file now ends with the ruling: record
|
|
182
|
+
the rule, the lengths and the narrowing, never the subject. This is the first
|
|
183
|
+
entry written under it. The older wordings stay where they are, because editing
|
|
184
|
+
a published file does not unpublish it.
|
|
185
|
+
|
|
186
|
+
Coverage was asked of the change rather than asserted, since going from six
|
|
187
|
+
entries to five must not leave the sweep reporting PASS about what it no longer
|
|
188
|
+
looks for. The matcher was exercised per slot without needing any real name:
|
|
189
|
+
the list replaced by five planted names, each planted in text, five reds
|
|
190
|
+
required, and a negative control that stays clean. The sweep also prints the
|
|
191
|
+
list's size on every run, so the change is visible rather than silent, and the
|
|
192
|
+
gate self-test still refuses an emptied list. The window `minTokenLength` and
|
|
193
|
+
`maxTokenLength` is unchanged at 7 and 15: both are stored literals, neither is
|
|
194
|
+
derived from the list, and the removed entry sat at neither bound, so no
|
|
195
|
+
published number narrowed.
|
|
196
|
+
|
|
197
|
+
- **`numbers.allowed` admits four values the SERVER publishes about itself** — two
|
|
198
|
+
inside tool descriptions and two as bounds in its own input schemas — under one
|
|
199
|
+
general rule written into that file rather than a caption each, because a caption
|
|
200
|
+
per value is the construction the list exists to avoid. It is safe to state in
|
|
201
|
+
general terms because the sweep already refuses an allowed number that occurs
|
|
202
|
+
nowhere in the tree, so an exemption cannot outlive its reason.
|
|
203
|
+
|
|
204
|
+
- **Four statements about other people's licences were wrong, and they are the kind
|
|
205
|
+
a reader acts on.** Every one was verified against its own source before it was
|
|
206
|
+
changed, and each correction says that an earlier version had it wrong rather than
|
|
207
|
+
quietly reading better.
|
|
208
|
+
- **Share-alike reaches adaptations, not aggregations.** `SOURCES.md`, `NOTICE`
|
|
209
|
+
and `README.md` all said DELFI data must not be blended into a result under a
|
|
210
|
+
different licence. CC BY-SA 4.0 art. 3(b) is expressed only over Adapted
|
|
211
|
+
Material (art. 1(a)); showing licensed data beside another source's data is an
|
|
212
|
+
aggregation, and Creative Commons states in terms that the condition "applies
|
|
213
|
+
only for works considered adaptations under copyright law, not simply in
|
|
214
|
+
collections with other works". Worse than generous in two ways: art. 3(b)(3)
|
|
215
|
+
forbids imposing terms that restrict rights the licence grants, which is what
|
|
216
|
+
telling you an aggregation is forbidden does — and the rule as written condemned
|
|
217
|
+
this service, since a weather answer can name `["dwd","osm"]`.
|
|
218
|
+
- **The DELFI licence version was sourced to nothing.** Measured at both levels
|
|
219
|
+
on 2026-09-27: the GovData record for the realtime feed carries the unversioned
|
|
220
|
+
licence URI and an empty dataset-level licence, and the national access point's
|
|
221
|
+
own metadata reports the same unversioned term. The publisher's sibling feeds in
|
|
222
|
+
the same catalogue *are* versioned, so it states a version when it means one.
|
|
223
|
+
The page now names the family, shows the evidence, and says to treat the
|
|
224
|
+
share-alike as applying regardless — because the version decides what a
|
|
225
|
+
recipient may put on a derivative (art. 3(b)(1)), and 3.0 unported has no
|
|
226
|
+
express database-rights clause where 4.0 art. 4 does.
|
|
227
|
+
- **§ 7 DWD-Gesetz prescribes a duty, not a wording.** Fetched verbatim: the
|
|
228
|
+
section is headed *Quellenschutz*, requires distribution to be "nur unter
|
|
229
|
+
Angabe der Quelle zulässig" and sets no text — and its second sentence adds
|
|
230
|
+
that fuller protection under the Urheberrechtsgesetz "bleibt davon unberührt",
|
|
231
|
+
so attribution is the statute's minimum rather than the whole of what may be
|
|
232
|
+
owed. The three words come from the DWD's own guidance, which also permits the
|
|
233
|
+
logo form — so a reader told the statute fixes the characters might refuse a
|
|
234
|
+
form the publisher expressly allows.
|
|
235
|
+
- **`NOTICE` understated the ODbL duty, and it is the file that republishes
|
|
236
|
+
itself** (Apache-2.0 § 4(d) makes every downstream redistributor carry it). It
|
|
237
|
+
said "address results" where the predicate is which *table* answered — place
|
|
238
|
+
resolution falls through the gazetteer to the OSM tables, so any answer about a
|
|
239
|
+
place may be OSM-derived — and offered one extract where the § 4.6 offer covers
|
|
240
|
+
both addresses and points of interest.
|
|
241
|
+
|
|
242
|
+
### Fixed
|
|
243
|
+
|
|
244
|
+
- **Every external program these scripts run is now resolved to an absolute path
|
|
245
|
+
instead of being looked up on `$PATH`** (`scripts/tools.mjs`). `git`, `tar`,
|
|
246
|
+
`npm` and a `mkdir` were spawned by bare name, which means the environment — not
|
|
247
|
+
this repository — decided which program actually ran. That matters more here
|
|
248
|
+
than it would elsewhere: one of these scripts is the leak sweep that decides
|
|
249
|
+
whether a commit may be published, and another is the hygiene gate that reads
|
|
250
|
+
the tarball about to be uploaded to the registry. A gate whose implementation
|
|
251
|
+
the caller can substitute is not a gate. SonarCloud reported seven of the call
|
|
252
|
+
sites as `javascript:S4036` and the project's Security Rating on new code stood
|
|
253
|
+
at B because of them.
|
|
254
|
+
- `git` and `tar` now come from `/usr/bin` or `/bin` only. `/usr/local/bin` and
|
|
255
|
+
`/opt/homebrew/bin` are deliberately not searched: they are writable by the
|
|
256
|
+
logged-in user on a normal developer machine, so admitting them would
|
|
257
|
+
reinstate the substitution this change removes. A tool that is genuinely
|
|
258
|
+
elsewhere makes the scripts refuse and say where they looked, which is a
|
|
259
|
+
better failure than quietly running something else.
|
|
260
|
+
- `npm` is no longer treated as a program at all. It is a JavaScript file, so it
|
|
261
|
+
is run as `<absolute node> <absolute npm-cli.js>`; node's own path is
|
|
262
|
+
`process.execPath`, which nothing can substitute. `mkdir` was replaced by
|
|
263
|
+
`fs.mkdirSync` — no subprocess at all.
|
|
264
|
+
- **Twenty call sites changed, not the seven that were reported.** The other
|
|
265
|
+
thirteen are in the two self-tests, which SonarCloud does not analyse. Leaving
|
|
266
|
+
them would have left the rule true of the code and false of the repository,
|
|
267
|
+
and a rule with a quiet exemption is the one nobody remembers when adding the
|
|
268
|
+
next call. (Counted per file in the finished tree: `check-leaks.mjs` 2,
|
|
269
|
+
`check-tarball.mjs` 4, `npm-pack-json.mjs` 1 — Sonar's seven — then
|
|
270
|
+
`check-leaks.test.mjs` 3 and `check-tarball.test.mjs` 10. The first version of
|
|
271
|
+
this entry said nineteen, because it was counted with a single-line grep that
|
|
272
|
+
cannot see the one call whose program argument sits on its own line. A count
|
|
273
|
+
taken with the wrong instrument, in a release whose own subject is exactly
|
|
274
|
+
that.)
|
|
275
|
+
|
|
276
|
+
- **And the repair for that duplicated it, which the quality gate caught before
|
|
277
|
+
the merge.** The precondition was *copied* from one self-test into the other —
|
|
278
|
+
eleven lines — and SonarCloud failed the pull request on **3.1% duplication on
|
|
279
|
+
new code** against a 3% limit, over exactly that block. Copying was the wrong
|
|
280
|
+
half of the right idea: the answer was always one implementation used twice.
|
|
281
|
+
It now lives in `scripts/fixture-root.mjs` as `missingFixtureImports()`, and each
|
|
282
|
+
self-test keeps its own refusal wording, because the two name different builders
|
|
283
|
+
and exit by different routes — a difference that is real rather than incidental.
|
|
284
|
+
Re-proved in each: dropping `tools.mjs` from a caller's file list makes that file
|
|
285
|
+
refuse by name, and each names its own builder.
|
|
286
|
+
|
|
287
|
+
**Concentrating the guarantee doubled its blast radius, so it got the assertion
|
|
288
|
+
it never had.** One function now stands behind every self-test that uses it, so a
|
|
289
|
+
silent `return []` disarms all of them at once and restores the wrong-reason pass
|
|
290
|
+
that started this thread — a sweep that cannot start, reporting no findings. The
|
|
291
|
+
number of those callers is deliberately not written here or in the module: it grew
|
|
292
|
+
again inside this release, and the sentence that said "both" went stale unnoticed
|
|
293
|
+
in five places while the corrected wording lived in one. On an ordinary run they
|
|
294
|
+
only ever exercise the complete-fixture path, so
|
|
295
|
+
until now the "missing" branch was proved solely by hand-mutating a file list:
|
|
296
|
+
four times by two people, and never again by anything. Two cases cover both
|
|
297
|
+
directions on a temporary directory, and they are mutation-proved — a planted
|
|
298
|
+
`return []` reddens one, and ignoring the directory argument reddens both.
|
|
299
|
+
|
|
300
|
+
Worth recording as the shape rather than the incident. A missing precondition was
|
|
301
|
+
fixed by adding one; adding it introduced a duplicate of it; the gate caught the
|
|
302
|
+
duplicate. Three links, and every one of them was found by something other than
|
|
303
|
+
the test suite, which was green at each step. The file count in this entry moved
|
|
304
|
+
from twenty-eight to twenty-nine because of it, then to thirty when this release
|
|
305
|
+
added a source file of its own, and then to **thirty-two** as it added the generator's
|
|
306
|
+
self-test and the module they share. The first two were re-derived from `npm run test:tools` rather than
|
|
307
|
+
incremented by hand. The third was not, and the review round found it stale. The
|
|
308
|
+
fourth was not typed either: it was read out of `npm run test:tools`'s own output
|
|
309
|
+
and the edit refused to write a number the command did not report. That was a
|
|
310
|
+
one-off script in a scratchpad, not something this repository carries — said plainly
|
|
311
|
+
because an earlier draft of this very sentence claimed a committed artefact that
|
|
312
|
+
does not exist. This paragraph has been wrong before, and that was the first time
|
|
313
|
+
it invented an artefact rather than a number.
|
|
314
|
+
|
|
315
|
+
- **The leak sweep's own self-test had no precondition on the fixture it builds,
|
|
316
|
+
and reported a scope regression instead.** Both self-tests copy a named list of
|
|
317
|
+
files into a throwaway repository, and `tools.mjs` was missing from both lists.
|
|
318
|
+
`check-tarball.test.mjs` refused by name, which is what a precondition is for.
|
|
319
|
+
`check-leaks.test.mjs` had no such check: **measured**, three of its four cases
|
|
320
|
+
failed with messages about scope — "expected a clean exit, got 1", "the run does
|
|
321
|
+
not say which scope it used" — because every invocation died of
|
|
322
|
+
`ERR_MODULE_NOT_FOUND`, and the fourth case *passed*, since a sweep that cannot
|
|
323
|
+
start also cannot report a finding. That is worse than a red suite: it sends the
|
|
324
|
+
next reader after the ruleset instead of after a missing file. It now refuses by
|
|
325
|
+
name, proved by dropping the file again.
|
|
326
|
+
|
|
327
|
+
- **`npm_execpath` was trusted if it was merely absolute and ended in `.js`** —
|
|
328
|
+
which reversed this change's own thesis for npm. The decider had moved from
|
|
329
|
+
`$PATH` to an environment variable, and the local review demonstrated it by
|
|
330
|
+
pointing the variable at a hand-written file, which the tarball gate would then
|
|
331
|
+
have run as npm. The value must now also be *shaped* like npm's CLI, ending in
|
|
332
|
+
`node_modules/npm/bin/npm-cli.js`. What that does not claim, because a security
|
|
333
|
+
note that overstates its reach is worse than none: anyone who can both set your
|
|
334
|
+
environment and create a file at that path is still obeyed — and anyone able to
|
|
335
|
+
do both can usually substitute node itself. The narrowing is from "any writable
|
|
336
|
+
path" to "a path that looks like a real npm installation": **it stops accidents,
|
|
337
|
+
not an attacker**, and it is not a privilege barrier. An earlier draft said
|
|
338
|
+
"stray, mistaken or opportunistic", which the sentence after it contradicted — an
|
|
339
|
+
opportunistic value costs one `mkdir -p`.
|
|
340
|
+
|
|
341
|
+
- **`npmCliPath()` refused to find npm on a Homebrew Mac.** Its first draft knew
|
|
342
|
+
only the `../lib/node_modules/…` layout, which is what the GitHub-hosted runner
|
|
343
|
+
and nvm use — so it passed in CI and failed on a developer's machine, where
|
|
344
|
+
Homebrew puts npm under `../libexec/lib/node_modules/…`. Both layouts are tried
|
|
345
|
+
now, each from the given path and again through `realpathSync`, since a node
|
|
346
|
+
reached by a symlink resolves its siblings from the real location. Caught by the
|
|
347
|
+
new self-test on the first run, which is the argument for having written it.
|
|
348
|
+
|
|
349
|
+
- **The false-positive fix opened a worse false negative, and the second review
|
|
350
|
+
round caught it.** Excluding `RE.exec('git')` by putting a `(?<!\.)` lookbehind
|
|
351
|
+
in front of the whole alternation also excluded every *member-expression* spawn —
|
|
352
|
+
`child_process.execFileSync('git', …)`, `cp.execSync('git status')` — which is a
|
|
353
|
+
shape SonarJS does report and a contributor can write without doing anything
|
|
354
|
+
unusual. So a fix aimed at a shape nothing writes blinded the sweep to a shape
|
|
355
|
+
people do. The lookbehind now applies to the bare name `exec` alone, measured
|
|
356
|
+
over twelve shapes: the all-names form was wrong on four of them, this one on
|
|
357
|
+
none. The one trade it still makes — `obj.exec('git')`, a method named `exec` on
|
|
358
|
+
something that is not a regular expression — is in the limits list, because no
|
|
359
|
+
expression can tell it from `RE.exec('git')` without a parser. Both directions
|
|
360
|
+
are pinned in the preconditions now rather than left incidental, since a review
|
|
361
|
+
round changed this behaviour by accident once already.
|
|
362
|
+
|
|
363
|
+
Two smaller things fell out of it. The comment describing the lookbehind said
|
|
364
|
+
`(?!\.)` where the code says `(?<!\.)` — a look*ahead* there would match nothing
|
|
365
|
+
useful, so it was the one comment in the file that would mislead somebody
|
|
366
|
+
"fixing" the code to match it. And the worked examples added to document the
|
|
367
|
+
twelve shapes turned the file red, because an example of a bare call, spelled as
|
|
368
|
+
one, *is* a bare call as far as the sweep is concerned; they carry no quote
|
|
369
|
+
characters now. The sweep catching its own documentation is the least ambiguous
|
|
370
|
+
evidence available that the member-expression form works.
|
|
371
|
+
|
|
372
|
+
- **Two documents that enumerate the gates had gone stale in the same commit that
|
|
373
|
+
added one.** `CONTRIBUTING.md` said "four more checks exist, and CI runs all
|
|
374
|
+
four" — five now, and the new one was missing from the block a contributor is
|
|
375
|
+
sent to, which also made the next paragraph's "a fifth command" read as a
|
|
376
|
+
contradiction. The pull-request checklist named two gates as "the
|
|
377
|
+
public-repository gates", so a contributor following it would not have run the
|
|
378
|
+
sweep that exists to catch exactly the call they might be adding.
|
|
379
|
+
|
|
380
|
+
## [1.3.15] - 2026-09-27
|
|
381
|
+
|
|
382
|
+
The first release with features in it since the bridge got code. Three
|
|
383
|
+
capabilities, and the documentation caught up with a service that had quietly
|
|
384
|
+
grown past it.
|
|
385
|
+
|
|
386
|
+
**If you only use `npx -y viafrei`, nothing changes and nothing breaks.** No flag
|
|
387
|
+
was removed, no default moved, no exit code changed meaning. The three additions
|
|
388
|
+
are opt-in or invisible.
|
|
389
|
+
|
|
390
|
+
### Added
|
|
391
|
+
|
|
392
|
+
- **A contributor surface: `CODE_OF_CONDUCT.md`, three issue templates with a
|
|
393
|
+
chooser, and a pull request template.** The Code of Conduct is Contributor
|
|
394
|
+
Covenant 2.1, and a report with no GitHub account goes to the Impressum e-mail
|
|
395
|
+
rather than to the **postal** address printed there — that address is still a
|
|
396
|
+
visible placeholder, and a reporting route has to be one that works. The three
|
|
397
|
+
forms are a bug, an idea, and the one report this service cannot make about
|
|
398
|
+
itself: a tool answered and the answer was useless. Beside them the chooser
|
|
399
|
+
carries the three routes that are not forms — the private security advisory,
|
|
400
|
+
Discussions, and `SOURCES.md` for a data or licence question. None of these
|
|
401
|
+
existed in 1.3.12.
|
|
402
|
+
- **`VIAFREI_MCP_HEADER` sets HTTP headers from the environment.** Many MCP
|
|
403
|
+
clients can only give a command an `env` block, never arguments, which left
|
|
404
|
+
those users no way to send a header at all. It takes the same `Name: value`
|
|
405
|
+
syntax as `--header`, refuses the same transport-owned names, and separates
|
|
406
|
+
several headers with a **newline**, which can never appear in a header name or
|
|
407
|
+
value, so nothing you might need to send is unrepresentable - a comma, a
|
|
408
|
+
semicolon and a space all occur inside real header values. A `--header` of the
|
|
409
|
+
same name wins; one of a different name is added alongside. An error names
|
|
410
|
+
`VIAFREI_MCP_HEADER`, not the flag you did not type.
|
|
411
|
+
- **`Retry-After` is honoured on the single retry, with a cap.** Both legal forms
|
|
412
|
+
are read - a number of seconds and an HTTP-date - and a value that cannot be
|
|
413
|
+
parsed, or names a moment already past, falls back to the fixed delay instead
|
|
414
|
+
of throwing. **The cap is the per-request timeout**: a server answering
|
|
415
|
+
`Retry-After: 3600` does not make `npx viafrei` sit silently for an hour; the
|
|
416
|
+
retry is abandoned and the ordinary one-line failure, which already names the
|
|
417
|
+
URL and the status, stands. `429` is retried now that the delay it asks for is
|
|
418
|
+
respected - and **only when the header gives a usable delay**. A 429 carrying
|
|
419
|
+
nothing readable is not retried at all, because the only thing left would be the
|
|
420
|
+
fixed delay, and a fixed delay is what makes a rate limit worse. For the same
|
|
421
|
+
reason a *thrown* 429 is still not retryable: there the header is gone. A 503 in
|
|
422
|
+
the same state IS retried, and a test pins the difference so it cannot be
|
|
423
|
+
flattened by accident.
|
|
424
|
+
- **A pathless `--url` that gets a 404 is told where the endpoint usually is.**
|
|
425
|
+
`--url http://127.0.0.1:3000` now fails with `... HTTP 404 Not Found - the URL
|
|
426
|
+
has no path; the MCP endpoint is usually /mcp`. **It is a hint and not a
|
|
427
|
+
rewrite**: quietly appending the path would send the request somewhere nobody
|
|
428
|
+
asked for and hide a different mistake later. The hint appears only when the
|
|
429
|
+
path is empty or `/`, never on another status, and a URL that will not parse
|
|
430
|
+
skips the hint rather than making the failure message itself throw.
|
|
431
|
+
|
|
432
|
+
### Changed
|
|
433
|
+
|
|
434
|
+
- **The README leads with how to connect, and says why to build on it.** The page
|
|
435
|
+
opened by explaining that you probably do not need this package, which is true
|
|
436
|
+
and was the first thing a developer read. The three transports now come first,
|
|
437
|
+
with the address to use, and a section sets out what the service is actually
|
|
438
|
+
offering: one protocol in place of twenty-one sources from sixteen publishers,
|
|
439
|
+
the licence obligations travelling with each answer, machine-readable failures,
|
|
440
|
+
and answers in the language of the question.
|
|
441
|
+
- **The tool count was wrong and is now a capability table.** The page said
|
|
442
|
+
thirteen tools; the server registers **eighteen**. The five geocoding tools had
|
|
443
|
+
shipped on the platform before the previous bridge release was even cut. The
|
|
444
|
+
table groups tools by the question they answer, which is stable, and the page
|
|
445
|
+
still refuses to paste the catalogue itself - a published tarball cannot be
|
|
446
|
+
corrected, so `tools/list` on the running server remains the only source of
|
|
447
|
+
truth.
|
|
448
|
+
- **The one completeness claim the new table introduced was measured before it
|
|
449
|
+
shipped.** The Places row says "nationwide, all sixteen Länder", which no tool
|
|
450
|
+
reports and which would rot at a partial import - the same objection that removed
|
|
451
|
+
the two address figures under **Fixed** ("Two address figures nobody could check
|
|
452
|
+
are gone"). It was kept because it was measured
|
|
453
|
+
rather than inferred, and it now carries the date: on 2026-09-27 the service's own
|
|
454
|
+
per-Land verdict - which reads both OSM tables, names any missing Land and exits
|
|
455
|
+
non-zero on one - reported all sixteen imported with every row scoped to its Land,
|
|
456
|
+
and two address lookups in the two Länder least likely to have been staged —
|
|
457
|
+
Mecklenburg-Vorpommern and Saarland, asked in Rostock and Saarbrücken — both
|
|
458
|
+
answered through the public endpoint with `osm` in `_meta.sources`. `SOURCES.md` carries the measurement, and one caveat that nearly
|
|
459
|
+
misled it: a single address that does not resolve says nothing about its Land.
|
|
460
|
+
- **The README now says that a slow call may be a retried call.** A `429`, `502`,
|
|
461
|
+
`503` or `504` is tried again **once** after the delay the server asked for, as
|
|
462
|
+
is a connection that failed outright; a `429` with no usable `Retry-After`, and
|
|
463
|
+
any delay longer than the per-request timeout, are not retried at all. The page
|
|
464
|
+
also now says what that timeout does and does not bound, because the first draft
|
|
465
|
+
of the paragraph got it wrong in the direction a user would act on: it is attached
|
|
466
|
+
per HTTP request, so the second attempt gets a fresh one and so does each hop of a
|
|
467
|
+
same-origin redirect, and **no setting here caps the whole call**. Two drafts of
|
|
468
|
+
that one clause were wrong, in the same direction and in the sentence a reader
|
|
469
|
+
would act on: the first said a retried call "can never exceed the timeout you gave
|
|
470
|
+
it", and the correction that replaced it said to halve the timeout for a hard
|
|
471
|
+
ceiling — but two attempts plus a delay that may itself be as long as the timeout
|
|
472
|
+
is three times it, not two, and more again if the endpoint redirects. Both were
|
|
473
|
+
caught in review rather than published, which is the argument for rounds that cost
|
|
474
|
+
nothing, and the second is the sharper lesson: a corrected number is still a
|
|
475
|
+
number, and nothing was reading it. That behaviour shipped earlier and the
|
|
476
|
+
page did not mention it, so a user watching a call take longer than expected had
|
|
477
|
+
nothing to read. Nothing about the behaviour changed in this release.
|
|
478
|
+
- **Both examples on the page are now captured output rather than plausible
|
|
479
|
+
output.** The departures block is a real answer from `mcp.viafrei.de` on
|
|
480
|
+
2026-09-27, and the failure line is copied from a run.
|
|
481
|
+
- **The badge hosts are admitted to the leak ruleset as their own group, with
|
|
482
|
+
their one cost written down.** A shields.io badge is the only entry on that
|
|
483
|
+
allow-list that causes a request from somebody else's browser, so the ruleset
|
|
484
|
+
now says that, says the admission test, and says it is the reason to refuse the
|
|
485
|
+
next image host rather than to admit it by precedent. The list itself stays
|
|
486
|
+
sorted alphabetically rather than grouped, and the ruleset now says why: one flat
|
|
487
|
+
sorted list is what makes a duplicate, or a near-miss spelling of a host already
|
|
488
|
+
on it, visible at a glance.
|
|
489
|
+
- **`numbers.allowed` is back to six entries, and the two rules governing it are
|
|
490
|
+
separated.** A seventh was added during this release to accommodate two bare
|
|
491
|
+
millisecond literals, then removed once both were written `1_000`: an entry that
|
|
492
|
+
covers nothing in the tree is a caption pointing at a value, which is the one
|
|
493
|
+
thing the inverse construction exists to avoid. (The entry is not named here,
|
|
494
|
+
because naming it would put the bare form back in the tree and the sweep would
|
|
495
|
+
be right to say so — it said so about the first draft of this very bullet.) The ruleset now distinguishes **the rule** (an
|
|
496
|
+
entry occurs in the tree and is not an internal value — which `3600` and `9110`,
|
|
497
|
+
both prose in a comment, satisfy) from **the preference** (write a numeric
|
|
498
|
+
separator where one is available, so the literal never reaches the list at all).
|
|
499
|
+
Citing the second as if it were the first is what made the list look arbitrary
|
|
500
|
+
for one review round.
|
|
501
|
+
- **Two `allowedHosts` entries covering nothing are gone.** Bare `shields.io` and
|
|
502
|
+
bare `contributor-covenant.org` sat beside `img.shields.io` and
|
|
503
|
+
`www.contributor-covenant.org`, and no URL in the tree uses either; the bare
|
|
504
|
+
spellings occur only in prose about them, and the host extractor reads a
|
|
505
|
+
scheme-prefixed URL and nothing else. That is the same shape as the
|
|
506
|
+
allow-list number this release removed: an entry that permits nothing is a
|
|
507
|
+
permission nobody can audit. The history-residue block is also back to one line
|
|
508
|
+
per entry; reformatting it to five four-line objects changed no meaning and cost
|
|
509
|
+
twenty-five lines of diff in the file a reviewer reads hardest.
|
|
510
|
+
- **A re-wrap put a private name into a public file, and the sweep caught it —
|
|
511
|
+
which is also a demonstration of the one limit it declares loudest.** The gate
|
|
512
|
+
reads **one line at a time**, and says so in its own limits list. A paragraph
|
|
513
|
+
of this release's prose was re-flowed, and prose that had passed every earlier
|
|
514
|
+
run matched a live entry the moment the wrapping changed. Nothing was ever
|
|
515
|
+
published: it reached a working tree and no further. What the offending text
|
|
516
|
+
was is deliberately not recorded — `scripts/rules.json` says to record the
|
|
517
|
+
rule, the lengths and the narrowing and never the subject, because a
|
|
518
|
+
description narrows the candidate space for a live entry further than the hash
|
|
519
|
+
alone does, and this file cannot be unpublished. The lesson is the gate's, not
|
|
520
|
+
the prose's — a line-oriented scanner's verdict depends on where the wrapping
|
|
521
|
+
falls, so its PASS is about this wrapping and not about this text, and a
|
|
522
|
+
re-wrap is a change the sweep has to see again.
|
|
523
|
+
|
|
524
|
+
### Fixed
|
|
525
|
+
|
|
526
|
+
- **`package-lock.json` still said 1.3.12 while `package.json` said 1.3.15, and
|
|
527
|
+
nothing in this repository would have noticed.** Found in the last pre-push check
|
|
528
|
+
of the release, by reading the two files rather than the diff: seven review rounds
|
|
529
|
+
had confirmed the lockfile was *unchanged*, which is true and is not the same as
|
|
530
|
+
correct. The publish workflow asserts that the TAG and `package.json` agree and
|
|
531
|
+
says so in its own step name; no gate compares the lockfile to either, and the
|
|
532
|
+
lockfile is not in the published tarball, so the only thing that reads it is the
|
|
533
|
+
`npm ci` the release build runs. It is now 1.3.15, regenerated with
|
|
534
|
+
`--package-lock-only` so the change is exactly the two version fields and no
|
|
535
|
+
dependency moved. **The missing gate is deliberately not added here**: it belongs
|
|
536
|
+
in `publish.yml`, and an untested edit to the workflow that publishes, inside the
|
|
537
|
+
commit it publishes from, is the wrong trade a day before the tag — it is filed
|
|
538
|
+
for the next release and rehearsed through the `workflow_dispatch` dry run, beside
|
|
539
|
+
the two other workflow items this release also deferred.
|
|
540
|
+
- **SOURCES.md described a service three capabilities smaller than the one that
|
|
541
|
+
is running.** Address lookup, lift and escalator status, and public-transport
|
|
542
|
+
realtime were all documented as not answering on the public service. All three
|
|
543
|
+
answer, and each was re-confirmed by a call whose result named the source. The
|
|
544
|
+
BKG administrative gazetteer was listed as merely licence-read and is in fact
|
|
545
|
+
named by answers from five different tools. Every status in the catalogue was
|
|
546
|
+
re-measured on 2026-09-27 by calling **fifteen of the server's sixteen
|
|
547
|
+
read-only tools** - every one except `find_cheapest_fuel` - once each and
|
|
548
|
+
reading `_meta.sources`. That one exception is **fuel**, which is deliberately not
|
|
549
|
+
re-measured because MTS-K sets a per-station floor and its terms make needless
|
|
550
|
+
querying a risk to the access itself. That row is labelled `not re-measured`
|
|
551
|
+
rather than dressed up as today's measurement.
|
|
552
|
+
- **SOURCES.md contradicted itself, and one of the contradictions was a licence
|
|
553
|
+
statement.** The table was re-measured; three paragraphs beneath it were not,
|
|
554
|
+
and they still told a reader that address lookup, facility status and
|
|
555
|
+
public-transport realtime do not answer. The worst of them sat in the ODbL
|
|
556
|
+
obligations section and said a share-alike obligation *"binds nobody using that
|
|
557
|
+
service right now"* - measurably false, on the one page whose job is to state
|
|
558
|
+
obligations, inside a tarball that cannot be corrected after publication. Every
|
|
559
|
+
such paragraph now states today's measurement and says which of the two
|
|
560
|
+
versions a reader saw. The status legend lost the value no row carries any more,
|
|
561
|
+
rather than leaving a status somebody could still be relying on.
|
|
562
|
+
- **The README promised rail disruptions "on a line or at a stop".** The server
|
|
563
|
+
declares the opposite in its own tool description and in `viafrei://coverage`:
|
|
564
|
+
it never answers whether a named line, trip or stop is on time. The row now says
|
|
565
|
+
region-wide and says never one line or stop.
|
|
566
|
+
- **Two address figures nobody could check are gone.** The Places row quoted a
|
|
567
|
+
count of addresses and POIs that no tool reports and that would rot at the next
|
|
568
|
+
import - the exact argument the paragraph below it makes against pasting a
|
|
569
|
+
catalogue.
|
|
570
|
+
- **The departures example names both of its edits.** It said the only edit was
|
|
571
|
+
shortening two URIs; five of the ten departures were dropped as well.
|
|
572
|
+
- **The OSM attribution line printed in `SOURCES.md` was not the line the server
|
|
573
|
+
emits.** The code fence said `Geokodierung: …`; no answer has carried that prefix
|
|
574
|
+
since `find_poi` and `find_address` began returning an OSM row **as** the answer
|
|
575
|
+
— a name, a brand, a door — rather than only a coordinate resolved from one. The
|
|
576
|
+
correct line is `OSM-Standortdaten: © OpenStreetMap-Mitwirkende, ODbL 1.0`, and
|
|
577
|
+
1.3.12 carried it nowhere: the page was wrong about the one string it exists to
|
|
578
|
+
publish, inside a tarball that cannot be corrected. A draft of this release then
|
|
579
|
+
printed both spellings at once, which is how it was caught. Every other fenced
|
|
580
|
+
attribution line was swept against the server's register; this was the only
|
|
581
|
+
mismatch.
|
|
582
|
+
- **"An answer about a place does not carry the ODbL line" — three words missing,
|
|
583
|
+
and the sentence reverses.** That wording is this release's own: 1.3.12 carried a
|
|
584
|
+
different wrong version of the same sentence (see the bullet below), and this one
|
|
585
|
+
was written while fixing that one and caught in review. The platform's own
|
|
586
|
+
wording is "a result about a
|
|
587
|
+
place **from our own gazetteer**, a station or a motorway is not built from
|
|
588
|
+
OpenStreetMap". Place resolution falls through the gazetteer to `osm_pois` and
|
|
589
|
+
then `osm_addresses`, so **every** tool that takes a `place` can return an
|
|
590
|
+
OSM-derived answer: measured on 2026-09-27, a weather warning for
|
|
591
|
+
`Zeiss-Großplanetarium` named `["dwd","osm"]` and carried the line, and one for
|
|
592
|
+
`Allianz Arena` named `["osm"]` alone. Both places on this page now carry the
|
|
593
|
+
qualifier and state the predicate — **which table answered**, not which tool
|
|
594
|
+
was called. Two wrong versions of this sentence have now been caught, and both
|
|
595
|
+
erred towards telling a reader an obligation did not apply to them. The last
|
|
596
|
+
round found the same error in the two places nobody re-reads after fixing a
|
|
597
|
+
paragraph: the **section heading** and its opening sentence still framed the
|
|
598
|
+
obligation as something that applies "if you get an address or a point of
|
|
599
|
+
interest back", so a reader who scans headings could conclude the section was
|
|
600
|
+
not theirs. Heading, lead and both bodies now state the predicate, and the
|
|
601
|
+
back-reference to the section was moved in the same edit as the heading.
|
|
602
|
+
- **Twenty-one sources, not nineteen — and the table was missing a row it needs
|
|
603
|
+
to be the register it claims to be.** This release added the station car parks
|
|
604
|
+
row and recorded it in its own bullet below, without correcting the number it
|
|
605
|
+
invalidated; the review
|
|
606
|
+
then found the DELFI disruption feed has a licence row in the server's register
|
|
607
|
+
and no row here. It is in the table now, `read`, at **CC BY-SA 4.0**. Re-counted
|
|
608
|
+
by hand: 21 rows, 16 distinct publisher cells. The README's dare — "count them
|
|
609
|
+
in that table" — is a good one and now survives being taken up.
|
|
610
|
+
- **The cleared-but-unused DELFI sentence was wrong in both halves, and it is a
|
|
611
|
+
licence statement.** It said "two more DELFI datasets … both CC BY 4.0 — the
|
|
612
|
+
share-alike is on the realtime feed". There are **three**, and two of them are
|
|
613
|
+
share-alike: the trip updates we serve and the disruption reports we do not.
|
|
614
|
+
Anybody planning for the day the disruption feed appears was being told to plan
|
|
615
|
+
for CC BY.
|
|
616
|
+
- **The station car parks row had no attribution line, on a page that promises one
|
|
617
|
+
per source** — a defect this release created and closed. 1.3.12 has no car-parks
|
|
618
|
+
row anywhere, and its "three products" sentence was correct for what it listed;
|
|
619
|
+
adding the row, in the bullet that raised the source count, made that sentence wrong, so the Deutsche Bahn
|
|
620
|
+
section said "three products · CC BY 4.0" over four products and two licences. Both fixed, with the BahnPark attribution
|
|
621
|
+
line written out — `read`, so no answer carries it today, and it is here so
|
|
622
|
+
nobody has to go looking on the day one does.
|
|
623
|
+
- **"No tool exposes the police traffic events yet" was a claim about the code,
|
|
624
|
+
and the code says otherwise.** That sentence is also this release's own — 1.3.12
|
|
625
|
+
carries the row at `read` and says nothing about reach. The road analysis already reads that feed, and
|
|
626
|
+
whether a source is NAMED is gated on a live catalogue row, so the row could
|
|
627
|
+
start carrying its attribution line with no release at all. The page now says
|
|
628
|
+
what it measured — `check_road_status` on the A40, A3, A1, A57 and A46 named
|
|
629
|
+
only the motorway interface and the BASt roadworks feed — and says out loud
|
|
630
|
+
that this is a statement about answers and not about reach. The row therefore
|
|
631
|
+
reads `in the service` and not `read`, and the page says not to design around
|
|
632
|
+
it.
|
|
633
|
+
- **Two dead intra-document anchors, both created by this release's own
|
|
634
|
+
corrections.** The `no API key` badge — on the npm package page and the
|
|
635
|
+
repository front page — pointed at `#quick-start`, a heading this release
|
|
636
|
+
renamed to "Connect in one line"; and `SOURCES.md`'s back-reference to the
|
|
637
|
+
§ 4.6 offer kept the old slug of a heading the previous review round renamed.
|
|
638
|
+
Every intra-document link in the tree was checked; these were the only two, and
|
|
639
|
+
both were ours. A later round found the shape that sweep could not see: an
|
|
640
|
+
issue **form** renders at `/issues/new?template=idea.yml`, so the relative
|
|
641
|
+
`../../blob/main/SOURCES.md` in it resolved one level short of the repository
|
|
642
|
+
and 404ed. It is an absolute URL now, like the one `config.yml` already used
|
|
643
|
+
for the same document.
|
|
644
|
+
- **The one place where `SOURCES.md` is now NEWER than the server's register is
|
|
645
|
+
named on the page.** BKG is `live` there on five measured answers, while
|
|
646
|
+
`viafrei://attribution` still flags it as planned — "licence read, data not
|
|
647
|
+
ingested yet". The page's own rule is that the resource wins and the page is
|
|
648
|
+
stale; that rule is right in general and wrong for this row today, so both the
|
|
649
|
+
rule and the row now say so. No bridge release can close it: it is tracked where
|
|
650
|
+
the server is developed, and what a reader of the published page can act on is
|
|
651
|
+
the answer itself - `_meta.sources` and the attribution lines it carries.
|
|
652
|
+
- **The charging answer does not count the sites without a status.** The page said
|
|
653
|
+
"a result says how many nearby sites had no status". It marks each one
|
|
654
|
+
`keine Statusdaten` and closes by saying that means unknown and not free —
|
|
655
|
+
measured, asking for Leipzig. What it refuses to do is leave them out or call
|
|
656
|
+
them free, which is the part that matters when you act on the answer.
|
|
657
|
+
- **The test for "which answers carry the ODbL line" was the question, and it
|
|
658
|
+
should have been the answer.** `SOURCES.md` said the line is carried "on every
|
|
659
|
+
answer whose input was an address, and on no other answer". `find_poi` asked for
|
|
660
|
+
a name and a city returns `_meta.sources: ["osm"]` and the line — so a reader
|
|
661
|
+
using that sentence to decide whether a share-alike obligation had arisen would
|
|
662
|
+
have concluded it had not. The rule is now stated as the platform states it, and
|
|
663
|
+
the page says to read `_meta.sources` on the answer rather than infer anything
|
|
664
|
+
from the shape of the question.
|
|
665
|
+
- **Our own § 4.6 offer was described more narrowly than it is.** It covers **both**
|
|
666
|
+
ODbL databases — addresses and points of interest, one file each under a single
|
|
667
|
+
licence notice — and the page named only the addresses. A recipient who derived
|
|
668
|
+
from POI results is entitled to the POI database.
|
|
669
|
+
- **The README promised car parking the public service does not answer.** Asked for
|
|
670
|
+
a `car_park` in Köln, Hamburg and Leipzig on 2026-09-27, every facility returned
|
|
671
|
+
was a lorry park or unclassified, and none carried occupancy. The row now says
|
|
672
|
+
lorry parking and a note says what is missing and why — the same over-claim as
|
|
673
|
+
the rail row, one row up, in the table this release rewrote to stop over-claiming.
|
|
674
|
+
- **The count of unconfirmed rows said two and there are three** — in a draft of
|
|
675
|
+
this release. 1.3.12 said **four**, counting a different set under a legend this
|
|
676
|
+
release replaced: under its own legend five rows said a source does not answer
|
|
677
|
+
today, and four was the number of `read` rows, which that legend defined as
|
|
678
|
+
"nothing uses it yet". The police-events row moved into the unconfirmed state
|
|
679
|
+
here, the changelog recorded the move and the count did not follow it. The station car-park source, in the server's register with no row
|
|
680
|
+
on the page at all, now has its `read` row.
|
|
681
|
+
- **The Code of Conduct sent a reporter without a GitHub account to a postal
|
|
682
|
+
address that does not exist** — in its first draft, in this release. The document
|
|
683
|
+
is new here (see `### Added`), so no published version ever sent anybody
|
|
684
|
+
anywhere. The Impressum's street and city are still visible placeholders; only
|
|
685
|
+
the e-mail address is real, and that is what the document names. Nothing linked
|
|
686
|
+
to it either; the README's Contributing section does.
|
|
687
|
+
|
|
6
688
|
## [1.3.12] - 2026-09-23
|
|
7
689
|
|
|
8
690
|
The bridge's code is unchanged since 0.0.9. This release replaces 1.3.10,
|
|
@@ -266,6 +948,8 @@ for it, so the number is free; the bridge will use it when the platform does.
|
|
|
266
948
|
commits, and a squash makes them unreachable from `main` - which would turn
|
|
267
949
|
the check red on `main` for everybody, for something no contributor did.
|
|
268
950
|
|
|
951
|
+
[1.3.16]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.16
|
|
952
|
+
[1.3.15]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.15
|
|
269
953
|
[1.3.12]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.12
|
|
270
954
|
[1.3.10]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v1.3.10
|
|
271
955
|
[0.0.9]: https://github.com/mavrovde/viafrei-bridge/releases/tag/v0.0.9
|