~bigbes/sr-ht-ecore

sr-ht-ecore/pages d---------
9a97b126 — Eugene Blikh 9 days ago
ecore: the gaps the third adoption pass found

Five services adopted the new packages today and each hit the same edges.

bearer.IsRefusal: a service's resolver returns more than this package's
vocabulary — the Postgres lookup it had to make, an expired context, a bug —
and StatusFor's default answers those 401, which tells a caller to re-mint a
token that was never the problem. Every service that wrapped the table spelled
out the sentinel list to guard the delegation; now it does not have to.

instconf.Key.Because: three services kept their own hand-written config
checker rather than lose the sentence that says WHY a key is required
("crypto.InitCrypto exits without it"). Require reported the names and nothing
an operator could act on, so nobody used it.

logging.DefaultsWithoutDebugFlag: a migration CLI passes -d to brant, where it
means --dialect and takes a value, so `coversrht-migrate -d postgres` arrived
as a request for debug logging — silently, because the probe sees the flag and
never the value.

assets.DirFS: os.DirFS("") does not mean "no assets", it means "serve the
filesystem root", and it is one unset config key away. dolt wrote the guard;
the other five would each have to see it happen first.

pages.APIMessage: the REST half of every service keeps its 404 body
byte-identical on purpose, so it could not adopt the shared refusal installer,
whose messages are page sentences. The same table now answers in both
registers.
3310ac7e — Eugene Blikh 9 days ago
bearer, pages: the refusal table and the form read that must not drift

bench wrote the bearer refusal switch three times in one repo — REST, MCP and
its resolver — and each copy re-decides the arm that matters: ErrUnavailable
is 503, never 401. Reading an unreachable token daemon as "revoked" tells
every CI job on the instance its credential is bad for as long as tokens.sr.ht
takes to restart. That warning has lived in this repo's README as prose, where
it cannot be imported; StatusFor puts it in code, and its default sends an
unrecognised failure to 401 so a forgotten arm refuses a request rather than
declaring the service unwell.

FormValues returns r.PostForm and never r.Form. r.Form merges the query string
into the body's values, so a mutation could be driven from a URL somebody was
linked to — the one request the same-origin guard cannot fault, because it did
come from our own page. The difference between the safe version and the hole
is one character in a field name, in a function every service with a form
writes for itself.
350dcb0b — Eugene Blikh 9 days ago
chrome: a default favicon, optional listing columns, and a table partial

Three services asked for a favicon field and bench argued against one: it
ships no icon deliberately, and its layout says why — a <link rel="icon">
pointing at an asset the binary does not have is a 404 on every page load, for
a file nobody asked for. A default that is a path hands that to every service
without a logo, so the default carries its own bytes instead: the brand's ring
as a data: URI, which cannot 404 and costs no request. It is a template.URL
because html/template rewrites any href whose scheme is not http, https or
mailto to "#ZgotmplZ" — the type is how a caller says it meant a data: URI.

Updated and Meta are optional for the reason the four listing services could
not agree: bench and spec have a modification time, dolt's schema has no
timestamp at all, and cover's index is a table of sparklines no shared partial
will render. A required column would have pushed dolt back onto a local copy.
Updated is a time.Time so the partial renders "3 hours ago" with the exact
stamp in the title once, rather than five services spelling it five ways.

srht-repo-table is a second partial over the same dot rather than a variadic
first one: growing columns on the cards would have made them worse cards for
the services that wanted cards.

Attach now installs Funcs itself, because the partials call reltime and
abstime and an unknown function is a parse error — a caller who had not merged
Funcs would have got a startup panic naming a template it never wrote. pages
consequently attaches before layering the service's own map on top, which is
what keeps a deliberate shadow working.
f019dbe4 — Eugene Blikh 9 days ago
middleware: report panics through slog

The two log.Printf lines were the last stdlib log in ecore, and they printed
a formatted sentence where every service on the instance now emits structured
records — a panic report that cannot be filtered by path or grouped by route
is the one log line an operator most wants to query.

Through slog's default logger rather than one handed to RecoverPanics: a
library has no business choosing a handler. The service installs scribe's at
startup with SetDefault, and these land in the same stream, with the same
masking, as its own lines.
996577de — Eugene Blikh 9 days ago
pages: the shared page set, buffered render and error page