From 71ca54e73615a541eefe2d287b1fa3afc539e49f Mon Sep 17 00:00:00 2001 From: burinc Date: Sun, 6 Sep 2026 22:49:18 +1000 Subject: [PATCH] feat(site): onboard docs-engine, publishing doc/ as the guide ebb had no docs/ directory at all - unlike raylib-android (which had full scaffolding, just disabled while the repo was private), this is a from-scratch onboarding. doc/evaluation.md, doc/conformance.md and doc/adr/001-fiber-affinity.md are real, reader-oriented documentation, not internal notes - but they are also load-bearing: test/ebb/conformance_test.clj hardcodes "doc/divergences.edn" and "doc/conformance.md" as its gate, and nine files under src/ebb/impl/ carry "See doc/conformance.md" comments. Moving them would mean rewriting that gate and a dozen-plus source comments. Instead docs/guide/{evaluation,conformance}.md and docs/guide/adr/001-fiber-affinity.md are relative symlinks into doc/, same pattern as awesome-jolt's guide/index.md -> README.md: doc/ stays the one canonical path every test and source comment already points at, and the site gets a window into it rather than a copy. docs/guide/index.md is a new page, not a symlink - ebb's README is already a GitHub-facing pitch (install, quick example, a four-line differences summary), so the guide gets its own "why this exists" overview that indexes the three real pages, matching glitter's own README-vs-guide/index.md split. Known gap, not fixed here: conformance.md's own prose links to divergences.edn (the machine-readable half of the same registry). That's an .edn file, not a doc page the engine renders, and publishing it as a site asset would mean rewriting that link in the canonical file the test suite reads verbatim - not worth doing to suit the site's layout. That one link 404s on the published site specifically; it's fine on GitHub, and the guide page's own prose says so and points there instead. .github/workflows/site.yml + docs/check-site.sh: build and publish via the org's shared jlt-commons/ci-builds reusable workflow. The checks include a byte-size floor on the two symlinked pages specifically, since a stale/broken symlink would still let the build succeed - slurp on a dangling link fails loud, but a symlink repointed at the wrong file would not. Verified locally against docs-engine v0.2.0: `bb build` succeeds, docs/check-site.sh passes (index, guide overview, evaluation, conformance and the ADR all present), and serving the build under /ebb/ (not root) returns 200 for all 10 emitted URLs with nothing escaping the base path. Confirmed the inherited cross-links between evaluation.md/conformance.md/the ADR (written assuming doc/'s own flat-plus-adr/ layout) correctly rewrite to .html at the same nesting depth under docs/guide/, and confirmed the divergences.edn gap is exactly that gap and nothing else (404, not a broader breakage). --- .github/workflows/site.yml | 35 +++++++++++++++++++ .gitignore | 5 +++ docs/check-site.sh | 45 ++++++++++++++++++++++++ docs/guide/adr/001-fiber-affinity.md | 1 + docs/guide/conformance.md | 1 + docs/guide/evaluation.md | 1 + docs/guide/index.md | 52 ++++++++++++++++++++++++++++ docs/site.edn | 22 ++++++++++++ 8 files changed, 162 insertions(+) create mode 100644 .github/workflows/site.yml create mode 100755 docs/check-site.sh create mode 120000 docs/guide/adr/001-fiber-affinity.md create mode 120000 docs/guide/conformance.md create mode 120000 docs/guide/evaluation.md create mode 100644 docs/guide/index.md create mode 100644 docs/site.edn diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml new file mode 100644 index 0000000..1acafe6 --- /dev/null +++ b/.github/workflows/site.yml @@ -0,0 +1,35 @@ +name: Site + +# Builds the documentation site on every pull request, and publishes it to +# GitHub Pages from main. +# +# The build itself lives in jlt-commons/ci-builds, shared by every project so +# the scaffolding is fixed in one place. What stays here is what is actually +# this project's: the content under docs/, its config in docs/site.edn, the +# base path below, and the assertions in docs/check-site.sh. + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +# Deploys must not race, and a half-applied Pages deployment is worse than a +# slightly stale one, so main is never cancelled. Pull request builds are +# scoped per ref and cancel their own earlier runs. +concurrency: + group: site-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + site: + uses: jlt-commons/ci-builds/.github/workflows/site.yml@main + with: + base-path: /ebb + permissions: + contents: read + pages: write + id-token: write diff --git a/.gitignore b/.gitignore index bd0c779..f37192c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,8 @@ # Agent instruction files: kept on a working copy, not published here. AGENTS.md CLAUDE.md + +# Generated documentation site (bb build, from a docs-engine checkout). +# Published by CI from main; never committed, since a stale build in the +# tree is worse than none. +_site/ diff --git a/docs/check-site.sh b/docs/check-site.sh new file mode 100755 index 0000000..a37a69f --- /dev/null +++ b/docs/check-site.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Assertions this project's documentation build must satisfy. +# +# Run by the shared site workflow in jlt-commons/ci-builds against the freshly +# built _site, with BASE_PATH exported. +# +# Run it locally the same way, from a docs-engine checkout: +# bb build && cd \ +# && BASE_PATH=/ebb bash docs/check-site.sh + +set -euo pipefail +out=_site + +test -f "$out/index.html" || { echo "no homepage generated"; exit 1; } +test -f "$out/guide/index.html" || { echo "no guide index generated"; exit 1; } +test -f "$out/guide/evaluation.html" || { echo "evaluation.md did not build"; exit 1; } +test -f "$out/guide/conformance.html" || { echo "conformance.md did not build"; exit 1; } +test -f "$out/guide/adr/001-fiber-affinity.html" || { echo "the ADR did not build"; exit 1; } +test -f "$out/css/screen.css" || { echo "static assets missing"; exit 1; } + +# docs/guide/{evaluation,conformance}.md and docs/guide/adr/001-fiber-affinity.md +# are symlinks into doc/ - the real files test/ebb/conformance_test.clj and a +# dozen src/ebb/impl/*.clj comments point at by that path. If a symlink ever +# goes stale (target renamed, doc/ restructured), the build still succeeds +# (a broken symlink just fails to slurp) but silently, so check the rendered +# content actually has weight rather than only checking the file exists. +for page in evaluation conformance; do + bytes=$(wc -c < "$out/guide/$page.html") + test "$bytes" -gt 2000 || { echo "guide/$page.html is suspiciously small ($bytes bytes) - stale symlink?"; exit 1; } +done + +! grep -rq '{{site-base}}' "$out"/index.html "$out"/404.html "$out"/guide/*.html "$out"/guide/adr/*.html \ + || { echo "unrendered template variable"; exit 1; } + +# The failure mode this site's base path exists to prevent. Served at +# jlt-commons.github.io/ebb/, a root-absolute URL loads the ORGANIZATION +# site's asset instead of this project's. The page still renders, wearing +# the wrong clothes, so nothing but a check catches it. +if grep -ohE '(href|src)="/[^"]*"' "$out"/index.html "$out"/404.html "$out"/guide/*.html "$out"/guide/adr/*.html \ + | grep -vE "=\"$BASE_PATH/"; then + echo "the URLs above escape $BASE_PATH and would resolve against the org site" + exit 1 +fi + +echo "build looks correct: index, guide overview, evaluation, conformance and the ADR all present, every URL under $BASE_PATH" diff --git a/docs/guide/adr/001-fiber-affinity.md b/docs/guide/adr/001-fiber-affinity.md new file mode 120000 index 0000000..b445100 --- /dev/null +++ b/docs/guide/adr/001-fiber-affinity.md @@ -0,0 +1 @@ +../../../doc/adr/001-fiber-affinity.md \ No newline at end of file diff --git a/docs/guide/conformance.md b/docs/guide/conformance.md new file mode 120000 index 0000000..fdd7217 --- /dev/null +++ b/docs/guide/conformance.md @@ -0,0 +1 @@ +../../doc/conformance.md \ No newline at end of file diff --git a/docs/guide/evaluation.md b/docs/guide/evaluation.md new file mode 120000 index 0000000..f93d774 --- /dev/null +++ b/docs/guide/evaluation.md @@ -0,0 +1 @@ +../../doc/evaluation.md \ No newline at end of file diff --git a/docs/guide/index.md b/docs/guide/index.md new file mode 100644 index 0000000..605e3b8 --- /dev/null +++ b/docs/guide/index.md @@ -0,0 +1,52 @@ +# ebb: Guide + +## Why this exists + +`ebb` is a port of [missionary](https://github.com/leonoel/missionary) to +[Jolt](https://github.com/jolt-lang/jolt): the same composable **tasks** (one +value, eventually) and **flows** (many values, with backpressure), the same +real cancellation and glitch-free dataflow propagation, running on Jolt's +Chez Scheme runtime over fibers instead of the JVM. Every public var of +missionary's API is supported, including the three process primitives `sp`, +`ap` and `cp`, the propagator and reactor, every port and flow operator, +`via`/`blk`/`cpu`, and `publisher`/`subscribe`. + +Missionary's own test namespaces run against ebb unmodified, except where +[conformance](conformance.md) says otherwise: 281 tests and 1187 assertions, +196 of those straight from missionary itself. + +## What's here + +- [Feasibility evaluation](evaluation.md) - written before the port started, + to decide whether it was possible at all. Its conclusions held; the + document is kept because its reasoning is why the code is shaped the way + it is. +- [ADR-001: Fiber affinity](adr/001-fiber-affinity.md) - the design that + grew out of the evaluation's central hazard. Six rules, and everything in + `impl/` follows them. +- [Conformance](conformance.md) - every observable difference from + missionary, exhaustive by design: a divergence missing from here is a bug + rather than a feature. The machine-readable half, + [divergences.edn](https://github.com/jlt-commons/ebb/blob/main/doc/divergences.edn), + is what `ebb.conformance-test` checks this page against on every test run - + read it on GitHub rather than here, since it's data, not a page. + +## Install and test + +Ebb needs Jolt v0.8.1 or newer. There's no release on Clojars yet; depend on +it as a git library by pinning a commit: + +```clojure +{:deps {jlt-commons/ebb {:git/url "https://github.com/jlt-commons/ebb" + :git/sha ""}}} +``` + +```bash +bin/test # the whole suite +bin/test ebb.rdv-test # one namespace +``` + +[CONTRIBUTING.md](https://github.com/jlt-commons/ebb/blob/main/CONTRIBUTING.md) +covers building, testing and porting, plus the conventions a change is +expected to follow. `model/README.md`, in the repo itself, holds core.logic +models that enumerate every interleaving of the concurrency design. diff --git a/docs/site.edn b/docs/site.edn new file mode 100644 index 0000000..84f3ff3 --- /dev/null +++ b/docs/site.edn @@ -0,0 +1,22 @@ +;; Configuration for the documentation site, read by the jlt-commons +;; docs-engine (https://github.com/jlt-commons/docs-engine). +;; +;; Build it locally from a docs-engine checkout with `bb build `, +;; or `bb serve ` to preview. CI builds and publishes it from +;; .github/workflows/site.yml, which calls the shared workflow in +;; jlt-commons/ci-builds. +{;; :base-path is what makes this a project site rather than an org one. The + ;; site is served at https://jlt-commons.github.io/ebb/, so every URL the + ;; engine emits needs that prefix. Leave it out and the pages still render, + ;; but each one loads the ORGANIZATION site's stylesheet and every image + ;; 404s. + :base-path "/ebb" + + :title "ebb" + :description "A functional effect and streaming system for Jolt: composable tasks and flows with real cancellation and glitch-free dataflow, running on Chez fibers. A port of missionary."} + +;; No :asset-dirs: this project has no images or demos to publish. +;; +;; No :home-template. docs/guide/index.md is a real overview page (not a +;; symlink to README.md, which is the shorter GitHub-facing pitch), so the +;; engine renders it as the generic homepage, TOC and all.