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.
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.
gitignore the dolt-git-hook build artifact
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
feat(web/beads): promote milestones to their own view/tab
Move the milestone rollup off the board and into a dedicated "Milestones" tab
(a registered View, companion to Beads via the same fingerprint). The tab is
richer than the old board panel: per-milestone progress bar, done/open/in-progress
counts, and the issue list under each milestone (open-work first, closed struck
through), each linking to its beads detail. Issues with no milestone label are
summarized in a footnote. A beads DB with no milestone labels still gets the tab,
showing an empty-state hint.
Removes the board's inline milestone panel and the collectMilestones/BeadMilestone
helpers it used; the grouping now lives in the milestones view.
feat(web/beads): ready markers, milestone rollup, transitive dependency tree
Three additions surfacing more of the bd data model:
- Ready: a ⚡ marker on actionable-now cards and a "Ready only" board filter.
"Ready" mirrors bd's ready set exactly — open, unblocked, not template/
ephemeral. As part of this, parent-child edges no longer count as blockers
(a subtask is not blocked by its open epic), which was over-filling Stalled
and under-counting ready; the board now matches bd's is_blocked/ready
accounting (verified: 111 ready on tarantool-etcd, == ready_issues).
- Milestone rollup: a board panel with per-"milestone:<name>" label progress
bars (done/total), each linking to that label's filtered board.
- Transitive dependency tree on the detail page: the full prerequisite chain
("everything this waits on") and the reverse ("everything this unblocks"),
walked from the edge set with depth/'node caps and cycle guard, indented by
depth. Shown only when it reaches past the direct edges, so it never just
repeats the flat Depends-on / Depended-on-by lists.
feat(web/beads): filters for the parade board
Add a filter bar to the beads board: text search (id/title), issue type,
priority, assignee, and label. Filters are query-param based (GET, sticky
across submits) and applied server-side before lane bucketing, so the marquee
counts reflect the filtered set. Dropdown options are collected from the full
issue set (they don't shrink as filters narrow the board); a Clear link shows
when any filter is active. Verified on the 143-issue tarantool-etcd board
(type=bug → 30).
feat(web/beads): close reason in Comments tab; synthesize subtask-add history
- Close reason placement: show it as a block at the end of the Comments tab
(which carries no closed event), while the History tab shows it inline as the
closed event — so it appears in whichever tab you're on, without duplication
within a tab. (Reverts the outright removal.)
- History now includes dependency/subtask additions. beads logs no audit event
for a link, but the dependencies row records created_at/created_by, so
buildDetail synthesizes "added subtask X" / "added dependency on X" timeline
entries (Kind "dep", own accent). On an epic this surfaces when each child was
linked. Guarded on created_at so older schemas without it emit nothing.
- pre.field-body style de-scoped from .bead-detail so the Comments-tab close
reason wraps (overflow-wrap: anywhere) instead of overflowing.
refine(web/beads): concise label events, drop standalone close reason, wrap long lines
- Label audit events collapse to one line ("added label milestone:m3") instead
of a "label added" header plus a redundant "Added label: …" body. The label
name is taken after the first colon so namespaced labels survive.
- Remove the standalone Close reason block below the activity: the reason
already shows as the History tab's `closed` event, so it was a duplicate.
- Add overflow-wrap: anywhere to the timeline body, comment body, and
field-body pre so a very long single-line reason wraps instead of overflowing.
feat(web/beads): epic view with subtask rollup, tabbed Comments/History
Three additions to the beads issue detail:
- Epic mode: when the viewed issue is issue_type=epic, render a Subtasks panel
— its parent-child children (deps pointing at the epic) with a done/total
progress meter, sorted open-work-first with closed sinking to the bottom.
- Activity is now a two-tab strip (pure-CSS, no JS): Comments keeps the plain
thread; History merges comments and the audit-log events table into one
time-sorted timeline with humanized change lines ("changed status to
in_progress", "updated priority to 0", "closed the issue" + reason).
- Close reason moved from the top metadata table to its own block at the very
bottom, after the activity — it reads as a closing note, not a header field.
Verified end-to-end against a real 143-issue beads store (tarantool-etcd) via
the env-guarded TestRealBeadsStore smoke test; unit-covered with a dedicated
epic/history fixture.