~bigbes/sr-ht-spec

6d7dbdb5 — Eugene Blikh 2 days ago
ci: publish this build's own coverage and benchmarks

Serving a revision is two passes over the whole corpus — FromDocuments builds
the archive, LinkPass renders every document to fill the link graph — and a
proposal view is a third over two whole revisions. All three grow with the
space rather than with the request, and this repository had no Benchmark at
all; doc/ and prosediff/ now measure them over a synthetic 208-document space
and a 24-chapter specification carrying one of every change kind.

The manifest gains a coverage and a bench task, both after publish so a
rejected upload cannot cost a shipped apk, and both guarded: the profile must
be non-empty, the benchmark names must be in the file (an empty benchfmt body
uploads and reports success), and a build handed no token says so and exits 0
with the artifact still attached.
ef7bddf8 — Eugene Blikh 3 days ago
ci: publish the apk into artifacts.sr.ht as well

The abuild output goes on to the S3 bucket phoebe re-indexes, and now also to
the ~bigbes/main channel of artifacts.sr.ht, which indexes and signs it in the
same request. One PUT per file with the shared working token; a 409 says the
job ran twice and is a warning rather than a failure.
6e59bf0f — Eugene Blikh 8 days ago
api: advertise an empty scope list, not null

core-go serves the second argument of WithSchema verbatim at
/query/api-meta.json, so a nil slice reaches the wire as `"scopes": null`.
meta.sr.ht discovers every *.sr.ht service at import time and iterates that
field when rendering /oauth2/personal-token, so the null turned the whole
instance's personal-token page into a 500 — no token could be minted at all
while spec.sr.ht was up. The other custom services answer 404 there and are
skipped, which is why only this one broke it.

Empty is the accurate value: the service is owner-only and defines no
AccessScope enum to grant against.
cb60d4f7 — Eugene Blikh 9 days ago
ci: run the suites against a real Postgres on the builder

93 test files across 16 packages had never run on builds.sr.ht. The manifest
brings up a Postgres in the VM, exports SPECSRHT_TEST_PG and runs gofmt, go vet
and `make test` before abuild.

The DSN guard is the point of it. db/db_test.go, service/fixture_test.go and
cmd/specsrht-migrate/main_test.go all gate on that variable, so an unset DSN
does not fail anything — it skips 67 tests (counted, with and against a local
Postgres) and leaves the build green over the whole persistence layer, the
schema/migrations agreement check included. options="!check" in the APKBUILD
means this task is the only place the suites run at all, so the guard is what
makes that line true.

TEST_TIMEOUT lands with it rather than after the first goroutine dump: the
toolchain's default is a silent ten minutes.
8255ff90 — Eugene Blikh 9 days ago
ci: export the version instead of sed-ing a tracked APKBUILD

The version reaches abuild as $PKGVER now, and the tracked APKBUILD is never
rewritten: Go reads vcs.modified from `git status --porcelain`, so a sed of a
tracked file stamps every packaged binary dirty for the whole abuild run.

The export alone would not have fixed it. .gitignore covered the intermediate
web/static/main.css and not the content-hashed main.min.<sha>.css that `make
css` renames it to — the file that survives, and that build() writes BEFORE go
build — so every packaging run compiled with an untracked file in the tree.
/src/, /pkg/ and /tmp/ are the three directories abuild works in inside this
checkout, GOTMPDIR among them.

Also: the cacher bootstrap splits into install + init so the installer's PATH
export is sourced by the next task, and goes through install.sh for its
checksum verification; scss collapses into the --exec miss-and-seed form;
cache_restore takes --optional plus the half-restored module cache repair;
cache_save moves after publish and drops the exists-guards; publish gates on a
readable ~/.apk-ci.env; tags build.

package() stages what build() produced (make install-files) instead of
recompiling both binaries in a fresh fakeroot process with no cache pins, and
stops installing static assets that //go:embed already put in the binary. The
`[ -d ./cmd/... ]` skip guards are gone: a deleted cmd/ was a green build that
packaged nothing.

The reasoning lives in docs/ci.md, because the manifest is a varchar(16384)
and a submission over the cap gets no CI at all.
9b5827b6 — Eugene Blikh 9 days ago
bearer: draw the 401 arm from IsAuthFailure so the two cannot drift
9cec0f54 — Eugene Blikh 9 days ago
deps: tidy after the third uplift
471d9706 — Eugene Blikh 9 days ago
chrome: the resolved favicon and the queue as a shared table
636dc7a8 — Eugene Blikh 9 days ago
pages: read a form's body, bounded, and never its URL
b643b0be — Eugene Blikh 9 days ago
bearer: refuse through the shared table and challenge
c87a11bd — Eugene Blikh 9 days ago
chimw: the request line, the HEAD twins and the routing refusals
0a32fd7a — Eugene Blikh 9 days ago
logging: take the instance's log policy from ecore
b7d1bf89 — Eugene Blikh 9 days ago
login: decode the unified-login cookie through ecore
be33cce1 — Eugene Blikh 9 days ago
instconf: one reading of this instance's origins
ed79a1bb — Eugene Blikh 9 days ago
deps: the ecore packages of the third uplift
cd1b8b01 — Eugene Blikh 9 days ago
deps: auxilia whose scribe.Err reads the whole error chain

Until now scribe.Err type-asserted the outermost error for slog.LogValuer,
so a culpa error under a single fmt.Errorf logged as a flat string and lost
its code, hint and stacktrace with no warning. It walks the chain now, which
is what makes the culpa wrapping in this service visible in the journal.
3d811988 — Eugene Blikh 9 days ago
service: wrap the merge and reject failures with culpa

Three sites, all of them the outermost wrap on an error that becomes a 500:
the merge path's non-staleness arm, the reject path's default arm, and the
merged-but-the-row-did-not case, whose remedy now rides on the error as a hint
instead of sitting in a sentence one wrap away from being buried.

Outermost is the whole criterion. scribe.Err type-asserts the error it is
handed for slog.LogValuer rather than searching the chain, so a culpa error with
an fmt.Errorf above it logs as a plain string and the stacktrace is lost — which
is also why the sentinel arms stay fmt.Errorf: they carry no cause worth a
stack, and their text is what a 404 or 409 shows a viewer.

errors.Is and errors.As traverse culpa's wrap, so the sentinel mapping in the
surfaces is unchanged.
643fa0b5 — Eugene Blikh 9 days ago
logging: log through slog and scribe rather than stdlib log

sr-ht-ecore's panic middleware now reports through log/slog, and it reports
through the *default* logger — nothing can hand a middleware in another module
this service's *slog.Logger. So the daemon's scribe handler becomes the one
install point, and the packages that were still calling log.Printf go through
the default logger too: the read plane's render and encode failures, its 5xx
mapping, and the credential resolver's fail-closed line. Each carries the fields
that used to be interpolated into the sentence — method, path, status, page,
doc — and the error itself through scribe.Err.

The handler grows what it was missing: file:line, because most of what reaches
it is a failure and 'which of the six render sites' is the first question;
colour dropped when stderr is not a terminal; and the masks. This daemon handles
the unified-login cookie and tokens.sr.ht working tokens, and a struct logged
whole is how a live credential outlives its own request in a log file — masking
in the handler covers the log line nobody reviewed as well as these.

cmd/specsrht-migrate keeps stdlib log on purpose: it is a one-shot CLI whose
'specsrht-migrate: ...' progress an operator reads at the terminal during an
upgrade, and log.Fatalf is its error exit.
3a56ee61 — Eugene Blikh 9 days ago
deps: bump sr-ht-ecore for the slog panic reporter

middleware now reports a recovered panic through log/slog with method, path,
panic and stack as fields instead of one stdlib log line. It logs through the
default logger, which is the next commit's business.
d4b6373d — Eugene Blikh 9 days ago
graph: seed the test keyset from ecoretest

The same fernet-key-and-webhook-seed TestMain the web package had, and the same
reason to delete it: ecore's keys are constants, so both packages of this
service can install them without the second rotating what the first sealed
with.
Next