~bigbes/sr-ht-dolt

22ba9fcd — Eugene Blikh 10 days ago
deps: bump sr-ht-ecore for slog panic reports

middleware reports a panic through slog's default logger now, with the
method, path, panic value and stack as attributes rather than one
formatted line. It logs through the default, so this service has to set
one — which the next commit does.
84c33df2 — Eugene Blikh 10 days ago
test: build the fixture config and the keyset with ecoretest

The hand-built ini in web_test.go, the random fernet key in authn's
TestMain and the same seeding copied into the git-hook test are one call
to ecoretest now. The keys are fixed rather than generated on purpose:
they secure nothing inside a test process, and a constant keyset is what
lets two packages of this service initialise without the second rotating
what the first sealed with.

The synthetic instance runs in production mode, so the environment
banner is off in tests unless one asks for it.
0af9ccda — Eugene Blikh 10 days ago
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.
17fa0f16 — Eugene Blikh 10 days ago
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".
f88846ac — Eugene Blikh 10 days ago
web: serve the static tree through ecore's assets

discoverStyleHref and the bare http.FileServer are sr-ht-ecore's assets
package now: one hashed-name pattern, the cache policy the hash implies
(immutable for a content-addressed name, an hour for the rest), and a
refusal to publish a directory listing of the build. The unhashed
fallback survives, but only when static/main.css is really there — an
href to a file this deployment does not ship is a 404 per page load,
which is what an empty Resolve exists to avoid.
bf7897cd — Eugene Blikh 10 days ago
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.
25541bcd — Eugene Blikh 10 days ago
gitignore the in-repo git worktree directories

Agent worktrees are created under .worktrees/<branch> (and, in the older
repos of this family, .claude/worktrees/<branch>) so that they never
scatter as sibling directories next to the checkout. Neither path was
ignored here, so a worktree showed up as untracked in every git status
taken from the main checkout.
e8a202e5 — Eugene Blikh 12 days ago
web: mirror the git twin's description onto companion databases

The internal create endpoint accepts a description, but its only caller
— dolt-git-hook — never sends one: git.sr.ht's push context does not
carry it. Companion databases therefore all sat descriptionless on the
dashboard while their git twins had perfectly good descriptions.

Resolve the description server-side instead: a GitDescriber dependency
(internal GraphQL query to git.sr.ht in the owner's name, the same
network-key trust the hook uses to reach us, pointed the other way) is
consulted on every /internal/repos call. A fresh companion is created
with the twin's description; for an existing one the push doubles as the
sync point — a changed, non-empty git description overwrites the stored
one. An empty git description never clobbers one set in dolt's own
settings, and every failure mode (no twin, git.sr.ht down, no resolver
wired) degrades to no mirroring. The lookup is capped at 3s so the
hook's own 5s POST timeout is never exceeded.

Adds testify as a direct dependency for the new tests.
8e7786cc — Eugene Blikh 12 days ago
gitignore the dolt-git-hook build artifact
1dc49e2e — Eugene Blikh 12 days ago
apk: ship dolt-git-hook as a -hook subpackage

The hook binary was the one piece of this repo not in the apk — the
deployment's Dockerfile.git cloned the repo and compiled it from source
at a separately pinned revision (SRHT_DOLT_HOOK_REV), which meant a
second version pin to keep in lockstep, a build-time dependency on the
git host, and a full Go toolchain stage in the git image rebuild.

Add dolt-git-hook to the Makefile's BINARIES (same guarded target
pattern) and split it into a dolt.sr.ht-hook subpackage: the git.sr.ht
container needs only this 9 MB binary, not the 126 MB doltsrht service
the main package carries. The deployment can now apk-add the subpackage
at the same pinned version as the service.
bb8ce43b — Eugene Blikh 12 days ago
web: restyle dashboard and database lists after git.sr.ht

Replace the bare 'Your databases' heading and compact grid with the
git.sr.ht dashboard layout: a sidebar column with a welcome blurb plus
block buttons (create database, configure dolt credentials), and the
shared event-list cards for the database list. The repoList partial now
renders each database as an event card — name, visibility as small
muted text (non-public only, like git.sr.ht), description below — and
the profile page picks the same partial up automatically.

Adds a 'lower' template func for the visibility label and drops the now
unused .repo-list grid from main.scss (.event-list ships with the core
theme already).
b5b08235 — Eugene Blikh 13 days ago
ci: cache the assembled scss tree

Move the cacher bootstrap to the first task and assemble the shared
sourcehut scss partials in ~/scss behind a cache keyed by
CORE_VER+BOOTSTRAP_REV. On a hit the build no longer talks to git.sr.ht
or github.com at all, so their outages can't fail it; a pin bump misses
and reassembles from source as before.
dbd8638d — Eugene Blikh 13 days ago
ci(apk): restore CORE_VER 0.84.5

The previous commit accidentally reverted 1760deb's core bump to
0.83.8 while splitting unrelated hunks; put 0.84.5 back.
93a10f48 — Eugene Blikh 13 days ago
ci: pin Go caches inside the APKBUILD, not the env

Builds #256/#257 failed in cache_save because abuild redirects GOCACHE
into its throwaway $tmpdir and an upstream typo in abuild.in assigns
GOMODCACHE from ${GOCACHE:-...}, so any GOMODCACHE exported beforehand
is clobbered. Exporting both paths inside build() runs after abuild's
own exports and therefore sticks; the buildenv exports are dropped.
1760debb — Eugene Blikh 13 days ago
ci(apk): build CSS against core 0.84.5

Tracks the srht deployment's SRHT_CORE_VER bump (unified project nav
added scss/nav.scss and reworked dark.scss). BOOTSTRAP_REV unchanged —
the bootstrap submodule did not move between 0.83.8 and 0.84.5.
dfd163e8 — Eugene Blikh 13 days ago
ci: pin Go caches to home dirs, abuild cleans srcdir

Build #256 failed in cache_save: abuild's default.conf redirects
GOMODCACHE/GOCACHE into $srcdir and wipes it after packaging, so the
restored caches were discarded and ~/go/pkg/mod never existed. Both
defaults use ${VAR:-...}, so exporting home-dir paths via ~/.buildenv
before abuild keeps the caches where cache_save expects them.
bfe53099 — Eugene Blikh 13 days ago
ci: cache Go module and build dirs via cacher

Restore ~/go/pkg/mod and ~/.cache/go-build from the Garage docker-cache
bucket before abuild and seed them back after, both keyed by go.sum via
the cacher helper (go.bigb.es/cacher), bootstrapped the same way as in
the bencher and ci-cacher builds. The dolt dependency tree dominates the
2m30s build step; a warm cache should cut it to well under a minute.
8527f0fd — Eugene Blikh 13 days ago
feat(web/beads): hierarchy in the milestone view

Arrange each milestone as a shallow hierarchy instead of a flat list.
- Put the milestone-typed issue(s) on top as the milestone's heads.
- Nest tasks under their epics via parent-child dependency edges,
  with a done/total rollup on the epic row; membership stays label-based.
- Keep remaining members as a loose tail; blocks edges are ignored.
- Read the dependencies table optionally, degrading to a flat list.
- Extend fixtures and real-data logging to cover the hierarchy.
5836cb69 — Eugene Blikh 13 days ago
ci(apk): commit the build, packaging and mirror-trigger files

These three were written but never committed, so the whole publishing chain
was dead from its first link: with no .build.yml on sourcecraft there is none
on the git.srht.bigb.es mirror either, so the push hook has no manifest to
submit, no build ever ran, and dolt.sr.ht has never appeared in the apk index
at repo.bigb.es — which today holds spec.sr.ht alone.

The code itself was mirroring fine, which is what made this hard to see: the
sourcehut side sits on the current commit, so everything looks configured
until you ask git which of these files it actually knows about.

.sourcecraft/webhooks.yaml is in the same state and has the same consequence
one level up: the gitsync webhook was never registered, so the mirror has been
riding its hourly safety-net poll rather than updating on push.

The build secret apk-ci-s3 the publish task needs now exists on the account,
so nothing else blocks the first build.
74d2612e — Eugene Blikh 25 days ago
fix(db): map repository_path_key to ErrNameTaken

CreateRepo only recognized uq_repo_owner_id_name as a name collision, but
path is derived from (owner, name) by RepoDiskPath, so a duplicate always
violates both indexes -- and repository_path_key, declared inline on the
column, has the lower OID and is the one Postgres reports. ErrNameTaken was
therefore unreachable in practice and every duplicate surfaced as a raw
23505, breaking all three callers that branch on it:

  - /internal/repos returned 500 "create database" instead of an idempotent
    200, so git.sr.ht's post-update hook printed "companion provisioning
    failed (500)" on every push to a repo whose companion already existed
  - the web create form returned 500 instead of 409 "You already have a
    database with that name."
  - a lost remotesapi auto-create race failed with codes.Unavailable
    instead of adopting the winner's row

TestCreateRepoDuplicateName missed it by re-creating under a different
path, which only the name index catches; it is now table-driven over both.
Next