50 ancestors of 5773517bde42071e
|
2026-08-16
| ||
| 16:17 |
artifact: an empty trailing token is legal on any card
Broadens the previous J/T/U fix: fossil's next_token() returns a non-NULL empty string whenever a card ends in a space, on any letter, and each card's own validation decides. C is the common case — 1,009 empty-comment artifacts across sqlite and tcl were rejected and demoted to content. Interior empty tokens stay malformed, and arity still gates the rest. check-in: 5773517bde user: dmestas tags: trunk | |
| 15:57 |
ingest: fold as we publish so a big census can't overrun the stream
ZITEVT is capped with DiscardOld, and watch() published the whole census in one burst — so a repo larger than the cap deleted its own head while the indexer was still folding, then reported itself done. sqlite indexed 41,478 of 131,558 artifacts and lost every ticket, wiki page and forum post. Publishing now yields to folding every 64 MiB. check-in: 44c86387b9 user: dmestas tags: trunk | |
| 15:57 |
artifact: accept an empty trailing card value
Real Fossil writes an empty value as a bare trailing space ("J comment ", "T +date <hash> "). The RFC grants this only for the U card, so quarry rejected the artifacts and demoted them to content — costing sqlite all 2,100 ticket changes. Tolerated on J/T/U only, trailing position only. check-in: 03858409ec user: dmestas tags: trunk | |
| 15:08 |
web: show indexing on the fleet page, and keep SSE alive across patches
A first index can run for minutes, so the home page showed a repo with zero check-ins and no explanation. Repos now carry an Indexing flag and the fleet row wears a badge until the first fold finishes. The badge exposed a live-update bug that had been there all along: data-init sat on the same element the stream patches. A patch morphs the target to match the fragment, the fragment has no data-init, so the first patch deleted Datastar's own connection attribute and the stream went quiet. The timeline had it too — masked because it only sends on change, so it appeared to work exactly once. The attribute now sits on a wrapper outside the patch target. check-in: 8e2eef5ab2 user: dmestas tags: trunk | |
| 13:44 |
markup: map fossil site-relative links; theme-neutral pikchr ink
Two bugs found by browsing real content on a phone. Imported wiki/technote/forum bodies are full of fossil's own routes (libfossil's wiki alone: 500 /finfo, 211 /dir, 105 /timeline, 23 /doc). Quarry passed those hrefs through verbatim, so libfossil's home page offered a README.md link that went nowhere. Resolver grows ResolvePath: /doc/<ver>/<path> maps to quarry's file route, /info to the artifact, /timeline /wiki /forum /technote to their pages; a verb quarry has no page for drops the link and keeps the label, since a dead link is worse than plain text. file.get now lets zit resolve symbolic versions (trunk, tip, tags) instead of demanding a hash — that is what /doc links use, and zit is the authority on names. The href rewrite runs BEFORE reference resolution so the two passes never see each other's output. Pikchr hardcodes rgb(0,0,0), which is invisible on quarry's dark theme — the DOM assertions all passed while the diagram was unreadable, and only a screenshot caught it. Its default ink now becomes currentColor so a diagram follows the page theme; author-specified colours are untouched. Fossil solves this with a server-side --dark-mode flag, which cannot work for a CSS-themed page. check-in: 1d680372e5 user: dmestas tags: trunk | |
| 12:53 |
markup: Pikchr diagrams via WebAssembly (fossil's third markup)
pikchr.c built to a standalone WASI module (-DPIKCHR_SHELL -sSTANDALONE_WASM) and run under wazero, so the CGO-free constraint holds. Its own CLI reads - and writes SVG, so the host ABI is a pipe: no memory marshalling to get wrong. Renders text/x-pikchr artifacts and pikchr fences inside markdown; a diagram that will not compile degrades to its source plus the compiler's message. SVG does NOT ride the document policy. It gets a narrow allow-list derived by enumerating what the module actually emits (six elements, a closed geometry/paint attribute set, no script/href/foreignObject), so even a hole in Pikchr's own label escaping cannot reach a page. Fence placeholders are alphanumeric with a per-render nonce: an HTML parser rewrites control bytes, so a NUL-based marker does not survive sanitizing (caught by test). Provenance and the rebuild recipe are in the ledger. check-in: 58fe4cf214 user: dmestas tags: trunk | |
| 12:45 |
markup: render Fossil wiki format; fix mimetype dispatch; GFM completeness
An absent N card means text/x-fossil-wiki, not markdown — fossil's wiki_render_by_mimetype is explicit — but quarry rendered those as markdown, mangling 217 of libfossil's 443 wiki artifacts ([target|label] links came out as literal text). Adds a Fossil wiki renderer (the seven rules from fossil's own wiki.wiki: paragraphs, single-level * and # lists, indented paragraphs, [target|label] links through the existing Resolver, verbatim/nowiki, HTML pass-through gated by the sanitizer), dispatches on mimetype exactly as fossil does, and stores forum posts' N card so they dispatch too. Fossil site-relative targets quarry cannot serve render their label as text rather than showing wiki source. Also GFM completeness: footnotes and auto heading IDs, with the sanitizer policy widened to admit what goldmark actually emits (a footnotes div, not section — caught by test). check-in: 45c96a506b user: dmestas tags: trunk | |
| 10:39 |
web: fit the timeline on phone widths
The card's metadata run was the widest line, so auto table layout preferred it, the table exceeded the viewport, and .tw scrolled sideways — putting the right-aligned check-in/user/branch off-screen on a 390px phone. Stack the meta items under 640px (max-content drops to the longest single item) and allow long comment titles to wrap. table-layout:fixed was tried first and rejected: it mis-sized the graph column to ~225px and squeezed cards to two words a line. Desktop is untouched; the graph lint stays clean at both widths. check-in: b43a9a7730 user: dmestas tags: trunk | |
| 10:29 |
technote: fold the C card and show it as the title
Technotes carry a C card (Fossil's timeline title) but the fold dropped it, so the timeline and listing showed raw 40-hex event ids — libfossil's real technotes read 'Technote: 0a83aac2...' instead of 'Project milestone: merge feature ported in'. Fold the comment, prefer it in the timeline and listing, and add it additively (ALTER, not a rebuild) for indexes created by the older schema. Also corrects a stale '-- C card' note on forum_post.body, which is the W card. check-in: 254d554df8 user: dmestas tags: trunk | |
| 10:21 | rfcs: v2 write plane — all four record types web-authored check-in: 4acdda438c user: dmestas tags: trunk | |
| 10:21 |
write plane: web-authored forum and technotes (v2)
forum.post/forum.reply/technote.add Command ops on zit#76's verbs, lease-guarded with read-your-writes and activity triggers; new-thread, reply, new-technote and technote-edit forms, all gated. Two correctness points: technote.add widens an event-id prefix to the full id (a prefix would mint a NEW technote instead of editing), and forum.reply shares forum.get's {root} path parameter (differing names on one template is invalid OpenAPI — spec-lint caught it). Fossil has the same surfaces (technoteedit, forumedit), so these are web faces of existing record types, not invented divergence. Wiki authoring already shipped earlier. Verified live in-browser: thread -> reply -> timeline, and technote edit superseding without duplicating. check-in: 4b68c8aae4 user: dmestas tags: trunk | |
| 10:05 | untrack fixtures/out clones swept in by addremove (build outputs, not source) check-in: 5e8de4dd50 user: dmestas tags: trunk | |
| 09:59 | remove stray quarry build artifact from tracking check-in: 6af3019d57 user: dmestas tags: trunk | |
| 09:57 |
chat: drop DAG archival — keep chat ephemeral like Fossil
Reversed 0001 §5's 'durability is the DAG': minting chat into synced, content-addressed forum artifacts writes casual chatter permanently into the DAG, the opposite of Fossil's deliberate chat ephemerality (server-local, auto-purged, never synced). Chat stays live + the 7-day JetStream window; durable archival becomes a future quarry-specific/S3 concern, not near-term. Removes internal/chatarchive, its wiring and flags, events.KV, and the zitcli forum/technote wrappers it used (they return with v2 web-authored forum). Chat itself is unchanged. check-in: 3d68e9b401 user: dmestas tags: trunk | |
| 05:17 | rfcs: chat forum-archival shipped (zit#76 landed) check-in: db788a07c6 user: dmestas tags: trunk | |
| 05:16 |
chat archival: fold chat into forum-thread artifacts (0001 §5 durability)
internal/chatarchive: batches a channel's messages (per N or T) and mints them as a 'Chat archive' forum thread through zit forum post/reply (zit#76) — one thread per channel, each batch a reply carrying the transcript, so history clones with the repo. Minting runs only on the lease holder; non-holders drop their buffers (the holder's archive folds back to every node). zitcli gains ForumPost/ForumReply/ TechnoteAdd. --chat-archive on by default. Verified live: chat batches materialize as forum threads and reply to the same thread. check-in: bd91af3158 user: dmestas tags: trunk | |
| 05:11 |
zitcli: use diff -R on bare stores (zit#69); re-tighten write ordering (zit#75)
zit diff now accepts -R for --from/--to, so quarry diffs bare stores without a checkout. Millisecond D cards restore real same-second write order, so TestWriteOps asserts strict last-write-wins again. check-in: 76b09e7fb8 user: dmestas tags: trunk | |
| 05:04 | rfcs: v1 shipped — chat and notify wiring complete check-in: f6f93c81cc user: dmestas tags: trunk | |
| 05:04 |
notify: fire mention and activity triggers to the notify companion (0001 §5)
internal/notify: a Novu-compatible POST /v1/events/trigger client (quarry triggers, notify owns delivery). chat.post parses @mentions and fires quarry-mention per handle; wiki/ticket write ops fire quarry-activity to a repo:<name> topic. All best-effort — a notify outage never fails the user action — with idempotency keys so replays dedup. --notify enables it (disabled by default). Verified live: mention and activity triggers POSTed with the right Novu shape. check-in: 37f62c9a82 user: dmestas tags: trunk | |
| 04:50 |
chat: per-repo live channel over NATS (0001 §5)
internal/chat: messages fan out over NATS with a 7-day JetStream window (replay on join), keyed by project code so a channel is shared across nodes. chat.history/chat.post ops (post is not lease-gated — it mutates no store); web page with on-load history, a plain post form (no-JS baseline), and an SSE append stream (Datastar enhancement). Verified live: form post + cross-connection SSE delivery in-browser, and cross-node fan-out on a shared external NATS. Durable forum-thread archival waits on zit forum verbs (zit#76); the window is interim durability. check-in: 5670d3643d user: dmestas tags: trunk | |
| 04:31 |
read plane: forum threads and technotes (v1 completion)
Fold Forum (G/H/I/W cards) and Technote (E/W cards) artifacts into forum_post/technote tables; forum.list/get and technote.list/get ops; threaded forum pages and technote pages through the sanitizer-gated markup pipeline; both kinds join the unified timeline (y=e|f) and nav. The parser already handled these types, so this is fold+render only. Verified against libfossil's real history: 35 forum threads, 26 technotes render, graph lint clean. check-in: c212383053 user: dmestas tags: trunk | |
| 04:06 |
reindex: --nats support for multi-node cluster rebuild
reindex was embedded-only, so a node's index could not be rebuilt in an external-NATS deployment (the durable position and shared cursor live in NATS, outside a node's --data). --nats routes reindex through the shared plane; the reset republishes the census that every node's fold absorbs. Validated on Linux/hetzner over external NATS. check-in: 87282e7532 user: dmestas tags: trunk | |
| 03:49 | rfcs: external NATS shipped, retention correction, trio status check-in: 9781c03cea user: dmestas tags: trunk | |
| 03:48 |
scale-out: external NATS + multi-node fan-out (trio part 1)
events.Connect joins an external NATS so N nodes share one plane; --nats selects it (embedded stays the single-node default). Retention switched work-queue -> limits+cap: work-queue load-balanced one copy across nodes, leaving each index partial; limits fans out to per-node durables (name now carries a hashed node id) while MaxBytes/MaxAge keep disk bounded. Lease refusals surface as 503 (ops.ErrUnavailable), not 500. Verified live: two nodes on one external NATS + shared store, each folds the full store, the leased node writes while the other 503s and still folds the write cross-node. check-in: 89e4991bbf user: dmestas tags: trunk | |
| 02:34 | rfcs: leases shipped; phase 4 complete; zit#74/#75 status check-in: 63ee2a682e user: dmestas tags: trunk | |
| 02:34 |
lease: single-writer coordination (0001 §3)
NATS KV TTL lease per store keyed by project code. Write ops and sync pushes route through Guard: renew-or-acquire, failover grace after displacing a holder, commit-point re-check before the write, and writes-refuse when the coordinator is unreachable (correctness over availability). Single-node holds its own lease with no grace delay; the machinery and failure posture are identical at N nodes. Tests: mutual exclusion, failover, coordinator-down refusal. check-in: d1436c2071 user: dmestas tags: trunk | |
| 02:18 |
security: close whitespace-card sync-gate bypass; write-op input 400s
Audit found a critical: scanRequest matched card keywords with a raw byte-prefix, so a push/login card indented by any Fossil-whitespace byte (SP/HTAB/VT/FF/CR) was invisible to the gate but still honored by the zit backend — an unauthenticated write to a gated repo. Now tokenizes exactly as zit's tokenizeCard (leading-whitespace-skipping), verified live. Also: gate GET edit/new pages (were ungated), reject control chars in wiki names (400 not 500), ticket.set no-fields 400 via new ops.ErrInvalid. check-in: 9db9b2ebae user: dmestas tags: trunk | |
| 02:07 |
rfcs: record shipped auth, retention, write path, interop status
0001 §7/§8: fossil-compatible §6 shared-secret login (not bearer tokens), work-queue stream retention, forge OLTP sync_user table. 0003: phase 0-4 status with cross-fossil interop results. check-in: 4788959dfa user: dmestas tags: trunk | |
| 01:05 |
write path: wiki/ticket ops, forms, Basic auth over sync secrets
wiki.save + ticket.new/set through zit#71 verbs with read-your-writes; edit/new pages; Token ops gate on HTTP Basic against the RFC-derived shared secret (same credentials as sync). Harness stores now carry authored wiki+tickets; wiki surfaces join disposability. check-in: 9005c16485 user: dmestas tags: trunk | |
|
2026-08-15
| ||
| 23:03 | web: /docs page serving the registry-generated API reference check-in: 216d15e366 user: dmestas tags: trunk | |
| 23:02 |
docs: API reference generated from the registry; staleness gate
quarry docs + make docs; TestDocsCurrent fails when docs/api.md drifts (0003: documentation is a phase exit criterion). check-in: fb2f393a1e user: dmestas tags: trunk | |
| 21:51 | oltp: drop redundant sqlite embed import check-in: cdb79b6675 user: dmestas tags: trunk | |
| 21:50 |
xfer: push gating with RFC §6 login verification; forge OLTP v1
quarry user add derives the shared secret via a clone handshake (project code, no .zit bytes) and stores it in oltp.db. Gated repos verify body or x-f-l-c cookie logins per request; pulls stay anonymous. Fossil pushes authenticate end-to-end; zit's client stops sending credentials after round 1 (zit#74) so its pushes fail closed until that lands. check-in: bcef58408e user: dmestas tags: trunk | |
| 21:30 |
xfer: sync fronting (0001 §7 v1 slice)
POST /r/{repo} (+/xfer alias) proxies to lazily-started per-repo zit serve children; dead children restart on the next request. E2E: clone through quarry, push back, watcher folds the push. Push auth waits for the forge-OLTP slice; leases stay v-next. check-in: 31b695c5cb user: dmestas tags: trunk | |
| 20:56 |
web: live fleet page; shared SSE patch loop
Home table morphs on any repo's change via Watch("*") wildcard. check-in: 0556d0b12c user: dmestas tags: trunk | |
| 20:54 | ticket.list: cursor pagination (updated~ticket), default 50 check-in: 6d7151de29 user: dmestas tags: trunk | |
| 20:45 |
web: escape wiki titles in every generated link
tcl's '(Initi/Fin)alize' page broke path routing; %2F keeps a slashed title one mux segment. check-in: 739eb90269 user: dmestas tags: trunk | |
| 20:40 |
wiki: edit history and revision views
wiki.history op + rev param on wiki.get; history page, historical- revision banner, timeline wiki rows link their exact revision. check-in: cadca370c1 user: dmestas tags: trunk | |
| 20:36 |
events: work-queue retention on ZITEVT; migrate old streams
Acked events leave the stream, so disk tracks the in-flight backlog, not store history (was 5.6GB beside sqlite's 218MB). Old-config streams are dropped with their cursors; the census republishes and idempotent folds converge. check-in: 14b0c96b83 user: dmestas tags: trunk | |
| 20:26 |
index: SQL-side ticket list fold; targeted TicketByPrefix
Full-history fold in Go took 1.3s per request on tcl (8.9k tickets). List now newest-updated first. check-in: 3dbf1759f6 user: dmestas tags: trunk | |
| 20:19 |
index: ticket_change(ticket) index; refresh ticket docs once per batch
tcl's ticket corpus crawled at ~20 changes/s: refreshTicketDoc scanned the whole table per change. check-in: 83fc12d336 user: dmestas tags: trunk | |
| 19:36 | ingest: consumer pending count decides drained, not a fetch timeout check-in: 29aa399eea user: dmestas tags: trunk | |
| 19:23 |
index: scale branch recompute to real stores
Indexed reverse parent edge + tag lookup; recursive walk lands in an indexed temp table before the UPDATE probe. sqlite.org's repo (36k check-ins) hung for 15+ min before; milliseconds path now. check-in: cd81fba74d user: dmestas tags: trunk | |
| 19:01 |
index: WAL + one branch recompute per fold round
Per-batch recursive-CTE recompute was quadratic over bulk ingest; rollback-journal mode locked readers out during folds. Adaptive fold MaxWait so backlog delivery lag isn't mistaken for drained. check-in: 6da2e08171 user: dmestas tags: trunk | |
| 18:48 | events: 8MB NATS payload cap for large-store artifacts check-in: 881e7d475e user: dmestas tags: trunk | |
| 18:33 |
phase 3: live timeline via Datastar SSE (Principle 3 enhancement)
events.Watch coalesces per-repo change ticks; composition root hands web a Notifier interface (planes stay sealed); timeline.sse re-renders the tl-body fragment through the op path and morphs #tl; vendored datastar v1.0.0-RC.7 (MIT, ledger row) is the page's only script; the no-JS page is unchanged. data-init, not the removed data-on-load. check-in: 263cff2b6b user: dmestas tags: trunk | |
| 18:23 | reindex: create the per-repo data dir check-in: 83dea2f98c user: dmestas tags: trunk | |
| 18:22 |
reindex verb: drop derived state and replay stores (0001 §5)
Pipeline.Reindex resets tables + deletes the KV cursor, then syncs; refolding streamed events is idempotent. CLI: quarry reindex --repo. check-in: 7124d5e366 user: dmestas tags: trunk | |
| 18:13 |
timeline: unified events — wiki and ticket rows interleave (y= filter)
Union query over checkin/wiki_edit/ticket_change (ticket titles from the folded search doc); composite date~hash cursor; flat event rows with badges, rails passing through; Show selector in controls. check-in: 4681b2fbc4 user: dmestas tags: trunk | |
| 18:04 |
timeline: branch lines one color fork-to-merge, uniform stroke
Look-ahead branch map colors merge rails by the commit they descend to; join curves keep their branch color to the fork; off-page parents render neutral, never a hashed hue for the empty name; drop vector-effect (zoom-variant thickness) for plain 2.5px strokes. Lint now checks color continuity at every cell boundary and stroke uniformity; unit tests pin the dev-line coloring end to end. check-in: 54f1834d26 user: dmestas tags: trunk | |
| 17:45 |
timeline: seamless graph tiling, date-row rail carry, mobile pass
Tail layer at fixed px width (was stretching to 100% — x misalign); head at top:0 with cy=24; date rows render active rails so pills sit beside an unbroken graph; 5px card gaps; mobile keeps vertical card padding so alignment holds. tools/timeline-verify.js is the browser geometric lint: 0 violations on all three demo repos at 1280 and 375. check-in: 994815316c user: dmestas tags: trunk | |