Render the landing page's plugin rows from the roster [#26] - #189
Merged
Conversation
The landing page said what this project is and listed none of the plugins it is about. Nothing in the tree held a roster to list them from, and no reading of the produced bytes told a page whose table was lost apart from a project that has no plugins. Entry 6 of #7 answered on 2026-08-24 that the site builds against a copy committed here and vendors the published file once it exists in the repository that holds the machine-readable data. So data/roster.json is a copy this repository authors for now, twelve rows taken from the table the organisation profile publishes, which is the other consumer of the same list. The parser asks whether each row's repository is there and refuses a read that skipped the question. Asking a host is a request off this machine, which a build may not make: it would produce different bytes on different days and fail with no network. data/repositories.json is that answer taken once, written down with the command that took it, and read from the tree. A row whose repository the record does not carry reds the build rather than rendering a link to nothing. The template gains the table and learns no count and no state word: the rows carry the words, and the sentence above them is composed where they are read. A tree that lost the roster is refused by name by the invariant gate, for the reason the claim about the clients already is. docs/roster-schema.md said that who lands the file is a question on the tracker. It is answered, and the document says where the bytes come from today and what the second file beside them is for. Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
The static analysis rule refuses a read whose path the line itself does not
show to be assembled, so that whether a path is whatever arrived is decidable
from the call rather than from every caller. Both reads took the path from a
variable one line above.
Ran 5 rules on 30 files: 2 findings.
internal/site/plugins.go
tools.semgrep.file-read-with-a-path-the-call-site-cannot-vouch-for
63: body, err := os.ReadFile(rosterPath)
111: body, err := os.ReadFile(p)
Run by the static analysis workflow on the head before this one.
Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
The landing page said what this project is and listed none of the plugins it is
about, because nothing in the tree held a roster to list them from:
Run 2026-08-25.
65353c6is the mainline this branch was cut from.What it waited on was entry 6 of #7, which asked who lands the file this board
only reads and what the build starts from. That entry is answered, on
2026-08-24:
Run 2026-08-25.
What this does
data/roster.jsoncarries twelve rows in the shapedocs/roster-schema.mddeclares. The content is taken from the table the organisation profile
publishes, which is the other consumer of the same list rather than a second
opinion about it:
Run 2026-08-25.
data/repositories.jsonis the recorded answer to the one question the rostercannot answer about itself. The parser asks whether each row's repository is
there and refuses a read that skipped it, and asking a host is a request off
this machine, which a build may not make: it would produce different bytes on
different days and fail with no network. So the answer is taken once, written
down with the command that took it, and read from the tree.
internal/site/plugins.goreads both and hands the page one entry per row. Thetemplate gains the table and learns no count and no state word: the rows carry
the words, and the sentence above them is composed where they are read, so a
thirteenth plugin is a row in a file and nothing else.
content/index.txtsaid of itself that it was the placeholder the pages wouldreplace with something that knows about a roster. It does now, so the paragraph
says what the table is and what a state word declares.
docs/roster-schema.mdsaid that who lands the file is a question on thetracker. It is answered, and the document now says where the bytes come from
today and what the second file beside it is for.
What this does not do, because it is somebody else's object rather than a
gap left open. The computed shipping state is #22 and none of it is here: the
table shows what a row declares, which the schema calls the floor rather than
the answer, and the page says so in as many words. The
requestsrow declaresshellwhile its repository has published one release, and that disagreement is#23, in this tree as well as in the manifest the catalogue serves; nothing here
decides it, and no check in this tree reads it yet. The comparison against the
organisation profile is #25. The per-plugin pages are #28.
Closes
Closes #26.
What was run
The gate, at the commit being pushed,
d622af5:No test was skipped, and none needed a display or elevation.
The rows match the roster, row for row
The identifier and the sentence of every row, out of the file and out of the
page, compared rather than eyeballed:
Run 2026-08-25 at
d622af5. Empty diff, twelve lines each side.Every line of the budget in #6 that this tree can read
Both run 2026-08-25 at
d622af5. Two lines of that budget are propertiesof a render rather than of the bytes, the largest contentful paint and the
layout shift, and neither is decided anywhere in this repository today; those
are #35, and this change moves neither of them. The stylesheet line still
decides nothing while no produced page carries one, which is the same reading
#26 already carried and is unchanged by the table.
The guards bite
The roster taken out of the tree, which is what losing the table looks like from
a page nobody read:
One repository dropped from the record, which is what the parser's question
exists to refuse:
The rows dropped on the way from the read to the page, which is the mistake the
suite exists for:
All three run 2026-08-25, each edit reverted before the next, and the tree
restored afterwards.
What the suite asserts that the runs above do not
A row added to the roster produces a row with nothing else edited. A sentence
carrying markup renders as text, with data that tries rather than with the data
this tree happens to hold. A state word the page has no words for reds the build
rather than reaching a reader as a bare identifier. And the read fails closed in
four ways: a row whose repository the record does not carry, a record carrying
no repository, a record saying nothing about when it was taken, and a roster
with no record beside it.
What a server check caught that this machine's gate did not
The first head of this branch was refused by the static analysis workflow, and
the refusal is recorded here rather than removed with the commit that repaired
it. Both reads took their path from a variable one line above, and the rule
refuses that so a reader can decide from the call whether a path is whatever
arrived:
Both are assembled at the call site on
d622af5. That leg is not part ofgo run . ci, which is why the gate on this machine was green over it, andthat gap is a property of the leg list rather than of this change.
The means
Go, the build verb and the invariant table this repository already carries.
The roster parser was already here and already fails closed; this change adds
its caller and adds no door beside it. JSON for both data files, which is what
docs/roster-schema.mdalready decided for the roster and what every other filethe build reads is written in. Nothing is added to the module graph: both new
files are read with
encoding/jsonand the rest is the standard library.The alternative refused was having the build ask the host whether each
repository is there. That is a request off the machine, so the build would stop
being reproducible and would fail with no network, which
decisions/0001-where-the-plugin-list-comes-from.mdalready refuses for therelease lists and for the same reason.
Who read it
Nobody but me. The ruleset requires no approving review, so this is merged by
whoever opened it, and the evidence above stands in place of a second reader.