web: tell a database outage from a missing database loadRepoForBrowse turned any error from GetRepoByOwnerAndName into a 404, so a metadata store that could not answer told every reader on the instance that their database does not exist — for as long as Postgres was down, in the voice reserved for "there is nothing here". loadRepoForAdmin did the same on the settings page. Both classify through repoLookupFailed now: db.ErrNotFound keeps the 404, and it stays the same 404 the visibility rule renders for a PRIVATE database the caller may not see, so a masked database and a missing one remain indistinguishable. Anything else is a 500 through the shared error page, with the cause logged (slog + scribe.Err) and never rendered.
pages: read forms through FormValues Every mutation on this surface read its fields with r.PostFormValue after a bare r.ParseForm. PostFormValue was already the right half — r.Form would merge the query string into the body, which would let a mutation be driven from a URL somebody was linked to, and that request is exactly the one the same-origin guard sees nothing wrong with — but the body was bounded only by net/http's 10 MiB default, on pages anyone can reach. FormValues is both properties in one call, and the values are passed down explicitly instead of each sub-handler reaching back into the request.
web: guard mutations with ecore's csrf, cache and panic middleware checkSameOrigin and originMatches are gone, and with them the three per-handler calls that had to be remembered: csrf.Require sits over the whole browser group, so the mutating route added next year is guarded by being routed. The internal provisioning endpoint stays outside that group deliberately — it is a service-to-service POST with no Origin and its own network-key guard. middleware.PrivateCache marks every page as one no cache may reuse for the next viewer, which is only correct because the static handler opts out per asset once it has found the file. RecoverPanics answers a panic with the error page, and one that arrives after the response has started by dropping the connection rather than appending an error to half a document.
web: render through ecore's pages and its error page The page list, the per-page parse loop and the view-template loop are gone: pages discovers every file in templates/, so a page is registered by existing, and one that defines no content block is refused at startup rather than served as chrome around a hole. 404.html and 403.html are gone with them — the shared error page carries the same body, and its prose is deliberately the same for a database that is not there and one the viewer may not see. The renderer that replaced them closes a leak: the old one wrote "template render error: "+err.Error() into the response body, handing the viewer template names and field paths. pages answers a fixed sentence and returns the error for the log. reltime and abstime come from chrome.Funcs now; ours called every future instant "just now", where the shared one says "in 3 weeks".
web: draw the chrome from sr-ht-ecore The brand, the service switcher, the login block, the environment banner and the database listing were a local port of core.sr.ht's nav — one of five such ports on this instance, and they had already drifted. They are now sourcecraft.dev/bigbes/sr-ht-ecore/chrome, the one copy every custom service draws from. Deleted: web/chrome.go entire (navEntry, networkOrder, networkExcluded, buildNetwork, basePage, loginURL, logoutURL), templates/nav.html, templates/icons/circle.svg (ecore inlines the identical SVG), the repoList partial, and the local dict/shortHash duplicates. Added: one chrome.Service built in newApp from our config section with the hashed stylesheet href set on it, a chrome.Page per request through app.page, chrome.Attach on every template set, and chrome.Funcs as the base of the funcmap. Handlers embed chrome.Page in their view structs instead of copying its fields; the row browser sets ContainerClass to container-fluid, since its column count is the table's and not ours. Three behaviour changes come with ecore's policy, all deliberate: the profile link now prefers hub's ~username page when hub.sr.ht is configured (it was always meta's /profile), the brand carries a fixed 15rem min-width so the switcher starts at the same x on every service, and a binary built without a stylesheet renders bare rather than linking an empty href. The nav test went with the code it tested — ordering, exclusions and login URLs are ecore's to cover — and what replaced it asserts only what is ours: that pages are drawn through the chrome at all, and that the row browser is full-bleed. The auth path is untouched: a foreign bearer token is still accepted as a meta.sr.ht PAT.
rename module to sourcecraft.dev/bigbes/sr-ht-dolt; depend on sourcecraft sr-ht-core
web: router, handlers, and sourcehut chrome Chi route table per plan, SourceHut chrome port (nav/layout from core.sr.ht Bootstrap structure), dual-flow clone box, dolt-key association page with hash-fragment prefill, same-origin CSRF checks. Handlers depend on small injected interfaces (StoreManager, RepoStore, BrowseOpener, UserResolver) with production adapters included.