Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions apps/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,21 @@ committed output differs from what the current source produces. A hand-maintaine
drifts from the types consumers actually pin, and the drift stays invisible until someone follows it
into a compile error.

The site at <https://flare-dispatch.fractalbox.dev> is an Astro Starlight build of this directory.
Every page under [`src/content/docs/`](src/content/docs/) except the landing page is a relative
The site at <https://flare-dispatch.fractalbox.dev> is an Astro build of this directory. The product
page (`/`) and `/benchmarks/` are plain Astro pages in [`src/pages/`](src/pages/) with their own
layout and stylesheet; the documentation under `/docs/` is Starlight. `/benchmarks/` prices the
workload profiles in [`src/data/benchmarks.ts`](src/data/benchmarks.ts) through the cost engine
(`packages/core/src/cost.ts`) at build time. `public/_redirects` maps the
root-level docs paths (`/actions/…`, `/runs/`, `/substrate/…`) to their `/docs/` pages.

Every page under [`src/content/docs/docs/`](src/content/docs/docs/) except the docs overview is a relative
symbolic link to Markdown elsewhere in the repo — these guides, the run catalog, the action READMEs,
the specs and ADRs — so each file has one copy and reads the same on GitHub and on the site.
[`src/lib/pages.mjs`](src/lib/pages.mjs) derives each page's title and description from its first
heading and paragraph, and rewrites relative links to site URLs (or to GitHub, for files that are not
pages). The site also serves `/llms.txt` and `/llms-full.txt`, generated from the same pages.

To publish another file, add a symbolic link under `src/content/docs/` and a sidebar entry in
To publish another file, add a symbolic link under `src/content/docs/docs/` and a sidebar entry in
[`astro.config.mjs`](astro.config.mjs). The build fails on a broken internal link.

```sh
Expand Down
26 changes: 13 additions & 13 deletions apps/docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,36 @@ export default defineConfig({
errorOnLocalLinks: true,
exclude: ({ link }) =>
// Pages outside the docs collection.
["/llms.txt", "/llms-full.txt"].includes(link) ||
["/", "/benchmarks/", "/llms.txt", "/llms-full.txt"].includes(link) ||
// README.md pages served at their directory (src/lib/pages.mjs).
README_PAGES.has(link.replace(/#.*$/, "")),
}),
],
sidebar: [
{ label: "Overview", link: "/" },
{ label: "Overview", link: "/docs/" },
{
label: "GitHub Actions",
items: ["actions", "actions/flare-dispatch-action", "actions/deploy-dispatcher-action"],
items: ["docs/actions", "docs/actions/flare-dispatch-action", "docs/actions/deploy-dispatcher-action"],
},
{ label: "Run catalog", slug: "runs" },
{ label: "Run catalog", slug: "docs/runs" },
{
label: "Substrate",
items: [
"substrate",
"substrate/facade",
"substrate/grant-profiles",
"substrate/byoc-upgrade",
"substrate/contract-versioning",
"docs/substrate",
"docs/substrate/facade",
"docs/substrate/grant-profiles",
"docs/substrate/byoc-upgrade",
"docs/substrate/contract-versioning",
],
},
{ label: "API reference", items: [{ label: "Substrate facade", slug: "reference/substrate-contract" }] },
{ label: "API reference", items: [{ label: "Substrate facade", slug: "docs/reference/substrate-contract" }] },
{
label: "Design records",
collapsed: true,
items: [
{ label: "Dispatcher ADRs", collapsed: true, items: [{ autogenerate: { directory: "design/adr" } }] },
{ label: "Dispatcher specs", collapsed: true, items: [{ autogenerate: { directory: "design/dispatcher" } }] },
{ label: "Substrate specs", collapsed: true, items: [{ autogenerate: { directory: "design/substrate" } }] },
{ label: "Dispatcher ADRs", collapsed: true, items: [{ autogenerate: { directory: "docs/design/adr" } }] },
{ label: "Dispatcher specs", collapsed: true, items: [{ autogenerate: { directory: "docs/design/dispatcher" } }] },
{ label: "Substrate specs", collapsed: true, items: [{ autogenerate: { directory: "docs/design/substrate" } }] },
],
},
],
Expand Down
1 change: 1 addition & 0 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@fractalbox/merlion-themes": "file:vendor/merlion/fractalbox-merlion-themes-0.1.0.tgz",
"@fractalbox/merlion-view": "file:vendor/merlion/fractalbox-merlion-view-0.1.0.tgz",
"@fractalbox/merlion-wasm": "file:vendor/merlion/fractalbox-merlion-wasm-0.1.0.tgz",
"@fractalboxdev/flare-dispatch-core": "workspace:*",
"astro": "7.3.3",
"cookie": "2.0.1",
"starlight-links-validator": "0.26.0",
Expand Down
10 changes: 10 additions & 0 deletions apps/docs/public/_redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Root-level docs paths → their /docs/ pages; / is the product page. Workers static assets
# apply these before asset lookup.
/actions/* /docs/actions/:splat 301
/design/* /docs/design/:splat 301
/reference/* /docs/reference/:splat 301
/runs/ /docs/runs/ 301
/substrate/* /docs/substrate/:splat 301
/actions /docs/actions/ 301
/runs /docs/runs/ 301
/substrate /docs/substrate/ 301
32 changes: 32 additions & 0 deletions apps/docs/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/docs/public/logo-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
139 changes: 139 additions & 0 deletions apps/docs/src/components/landing/BillingTimeline.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
// Billing-model graphic for the landing page.
//
// One code-review run, billed two ways, on a single shared time axis:
// • GitHub Actions — the whole wall-clock run is billed, the idle LLM wait
// included (per-minute runner time).
// • FlareDispatch — only the vCPU-active slivers are billed; the model-wait
// runs in a Workflow step (CPU-time billed) and accrues no compute.
//
// Both bars use identical segment geometry, so the active slivers line up
// column-for-column. The only visual difference is whether the idle gaps are
// filled (billed) or empty (free) — that contrast *is* the argument.
//
// Segment widths are illustrative but proportionate: ~20% active, ~80% wait.

type Seg = { kind: "cpu" | "io"; w: number; label?: string };

const segments: Seg[] = [
{ kind: "cpu", w: 4, label: "setup" },
{ kind: "io", w: 17, label: "read diff" },
{ kind: "cpu", w: 3 },
{ kind: "io", w: 22, label: "review ①" },
{ kind: "cpu", w: 2 },
{ kind: "io", w: 21, label: "review ②" },
{ kind: "cpu", w: 2 },
{ kind: "io", w: 20, label: "synthesize" },
{ kind: "cpu", w: 9, label: "post" },
];

const total = segments.reduce((s, x) => s + x.w, 0);
const activePct = segments
.filter((s) => s.kind === "cpu")
.reduce((s, x) => s + x.w, 0);

const BX0 = 104;
const BX1 = 468;
const BW = BX1 - BX0;

let cursor = BX0;
const placed = segments.map((s) => {
const x = cursor;
const w = (s.w / total) * BW;
cursor += w;
return { ...s, x, w };
});

const GHA_Y = 62;
const FD_Y = 122;
const BAR_H = 38;
---

<figure class="billing" aria-labelledby="billing-caption">
<svg
class="billing__svg"
viewBox="0 0 540 232"
xmlns="http://www.w3.org/2000/svg"
role="img"
aria-label={`Billed time for one code-review run. GitHub Actions bills the entire wall-clock run, including the roughly ${total - activePct} percent spent waiting on the model. FlareDispatch bills only the roughly ${activePct} percent that is vCPU-active.`}
>
<text class="title" x="0" y="22">BILLED TIME · ONE CODE-REVIEW RUN</text>

<!-- vCPU-active columns, carried through both bars so the slivers align -->
{placed
.filter((s) => s.kind === "cpu")
.map((s) => (
<rect
class="col-active"
x={s.x}
y={GHA_Y}
width={s.w}
height={FD_Y + BAR_H - GHA_Y}
/>
))}

<!-- phase labels (the waits) above the top bar -->
{placed.map((s) =>
s.kind === "io" && s.label ? (
<text class="phase" x={s.x + s.w / 2} y={GHA_Y - 8} text-anchor="middle">
{s.label}
</text>
) : null,
)}

<!-- Bar 1: GitHub Actions — the whole run is billed, wait included -->
<text class="row-name" x="0" y={GHA_Y + 16}>GitHub</text>
<text class="row-name" x="0" y={GHA_Y + 28}>Actions</text>
{placed.map((s) => (
<rect
class={s.kind === "cpu" ? "seg-active" : "gha-wait"}
x={s.x}
y={GHA_Y}
width={s.w}
height={BAR_H}
/>
))}
<rect class="gha-frame" x={BX0} y={GHA_Y} width={BW} height={BAR_H} />
<text class="end-label end-label--gha" x={BX1 + 8} y={GHA_Y + BAR_H / 2 + 4}>
10 min
</text>

<!-- Bar 2: FlareDispatch — only the active slivers are billed -->
<text class="row-name row-name--fd" x="0" y={FD_Y + 16}>Flare</text>
<text class="row-name row-name--fd" x="0" y={FD_Y + 28}>Dispatch</text>
<rect class="fd-envelope" x={BX0} y={FD_Y} width={BW} height={BAR_H} />
{placed
.filter((s) => s.kind === "cpu")
.map((s) => (
<rect class="seg-active" x={s.x} y={FD_Y} width={s.w} height={BAR_H} />
))}
{placed
.filter((s) => s.kind === "io" && s.w > 50)
.map((s) => (
<text class="idle" x={s.x + s.w / 2} y={FD_Y + BAR_H / 2 + 3} text-anchor="middle">
free
</text>
))}
<text class="end-label end-label--fd" x={BX1 + 8} y={FD_Y + BAR_H / 2 + 4}>
~2 min
</text>

<!-- shared time axis -->
<line class="axis-line" x1={BX0} y1={FD_Y + BAR_H + 12} x2={BX1} y2={FD_Y + BAR_H + 12} />
<text class="axis" x={BX0} y={FD_Y + BAR_H + 26}>wall-clock time of one run →</text>

<!-- legend -->
<g class="legend" transform="translate(104, 214)">
<rect class="legend-swatch seg-active" x="0" y="-9" width="11" height="11" />
<text class="legend-label" x="17" y="0">vCPU-active — billed by both</text>
<rect class="legend-swatch legend-swatch--wait" x="210" y="-9" width="11" height="11" />
<text class="legend-label" x="227" y="0">LLM I/O wait — GitHub Actions only</text>
</g>
</svg>
<figcaption id="billing-caption" class="sr-only">
A code-review run is roughly {activePct}% vCPU-active and {total - activePct}%
LLM I/O wait. GitHub Actions bills the entire wall-clock run; FlareDispatch
bills only the vCPU-active fraction, because the model-wait runs in a
CPU-time-billed Workflow step.
</figcaption>
</figure>
81 changes: 81 additions & 0 deletions apps/docs/src/components/landing/HeroDiagram.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
// Decorative architecture SVG for the landing hero.
// Three triggers — a GitHub Actions workflow, a Cloudflare Cron schedule, or
// a GitHub App webhook — reach the Dispatcher Worker, which orchestrates a CF
// Workflow that fans out to Sandbox, Browser Rendering, and R2, then reports
// back to the GitHub Checks tab. Visualizes the offload thesis without a real
// Mermaid render.
---

<div class="hero__diagram" aria-hidden="true">
<svg viewBox="0 0 360 360" xmlns="http://www.w3.org/2000/svg">
<!-- Triggers -->
<circle class="node" cx="72" cy="46" r="28" />
<text class="label" x="72" y="44" text-anchor="middle">GHA</text>
<text class="label" x="72" y="56" text-anchor="middle">action</text>

<circle class="node" cx="180" cy="46" r="28" />
<text class="label" x="180" y="44" text-anchor="middle">CRON</text>
<text class="label" x="180" y="56" text-anchor="middle">schedule</text>

<circle class="node" cx="288" cy="46" r="28" />
<text class="label" x="288" y="44" text-anchor="middle">APP</text>
<text class="label" x="288" y="56" text-anchor="middle">webhook</text>

<!-- Dispatcher Worker -->
<circle class="node" cx="180" cy="142" r="44" />
<text class="label" x="180" y="138" text-anchor="middle">WORKER</text>
<text class="label" x="180" y="150" text-anchor="middle">/v1/dispatch</text>

<!-- Workflow -->
<circle class="node" cx="180" cy="240" r="34" />
<text class="label" x="180" y="238" text-anchor="middle">WORKFLOW</text>
<text class="label" x="180" y="250" text-anchor="middle">durable</text>

<!-- Data plane -->
<circle class="node agent" cx="62" cy="320" r="26" />
<text class="label" x="62" y="318" text-anchor="middle">SANDBOX</text>
<text class="label" x="62" y="330" text-anchor="middle">test</text>

<circle class="node agent" cx="180" cy="328" r="24" />
<text class="label" x="180" y="326" text-anchor="middle">BROWSER</text>
<text class="label" x="180" y="338" text-anchor="middle">e2e</text>

<circle class="node agent" cx="298" cy="320" r="26" />
<text class="label" x="298" y="318" text-anchor="middle">R2</text>
<text class="label" x="298" y="330" text-anchor="middle">cache</text>

<!-- Edges: triggers -> worker -->
<path class="edge" d="M92 70 L158 106" />
<path class="edge" d="M180 74 L180 98" />
<path class="edge" d="M268 70 L202 106" />

<!-- Worker -> Workflow -->
<path class="edge" d="M180 186 L180 206" />

<!-- Workflow -> data plane -->
<path class="edge agent" d="M158 264 L82 300" />
<path class="edge agent" d="M180 274 L180 304" />
<path class="edge agent" d="M202 264 L278 300" />

<!-- Check-run callback: Worker -> GHA -->
<path class="edge" d="M140 122 Q74 94 78 74" stroke-dasharray="3 3" />

<!-- Op-flow ticks -->
<g class="label" fill="currentColor">
<text x="104" y="92" font-size="8">▸ HMAC</text>
<text x="186" y="90" font-size="8">▸ cron</text>
<text x="214" y="92" font-size="8">▸ signed</text>
<text x="192" y="200" font-size="8">▸ step</text>
<text x="60" y="288" font-size="8">▸ run</text>
<text x="232" y="288" font-size="8">▸ artifact</text>
<text x="40" y="120" font-size="8">▸ check-run</text>
</g>

<!-- Hairline grid -->
<g stroke="currentColor" stroke-width="0.25" opacity="0.18">
<line x1="0" y1="180" x2="360" y2="180" />
<line x1="180" y1="0" x2="180" y2="360" />
</g>
</svg>
</div>

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion apps/docs/src/content/docs/actions/index.md

This file was deleted.

1 change: 0 additions & 1 deletion apps/docs/src/content/docs/design/adr

This file was deleted.

1 change: 0 additions & 1 deletion apps/docs/src/content/docs/design/dispatcher

This file was deleted.

1 change: 0 additions & 1 deletion apps/docs/src/content/docs/design/substrate

This file was deleted.

1 change: 1 addition & 0 deletions apps/docs/src/content/docs/docs/actions/index.md
1 change: 1 addition & 0 deletions apps/docs/src/content/docs/docs/design/adr
1 change: 1 addition & 0 deletions apps/docs/src/content/docs/docs/design/dispatcher
1 change: 1 addition & 0 deletions apps/docs/src/content/docs/docs/design/substrate
Loading
Loading